From d609db96add898f16daa234747e77af189e09132 Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Fri, 28 Aug 2026 21:43:16 +0530 Subject: [PATCH] Use php-darwin caches on macOS --- __tests__/utils.test.ts | 21 +++ dist/index.js | 2 +- src/install.ts | 2 +- src/scripts/darwin.sh | 10 ++ .../tools/php-darwin/conf/archive-paths | 5 + .../tools/php-darwin/conf/package.json | 12 ++ .../tools/php-darwin/conf/platforms.json | 16 ++ src/scripts/tools/php-darwin/conf/versions | 14 ++ .../php-darwin/scripts/existing-paths.sh | 52 ++++++ .../tools/php-darwin/scripts/extract.sh | 22 +++ .../tools/php-darwin/scripts/install.sh | 149 ++++++++++++++++ src/scripts/tools/php-darwin/scripts/lib.sh | 124 +++++++++++++ .../tools/php-darwin/scripts/registry.sh | 164 ++++++++++++++++++ .../tools/php-darwin/scripts/source-hash.sh | 33 ++++ .../php-darwin/templates/oci-descriptor.json | 8 + src/utils.ts | 9 + 16 files changed, 641 insertions(+), 2 deletions(-) create mode 100644 src/scripts/tools/php-darwin/conf/archive-paths create mode 100644 src/scripts/tools/php-darwin/conf/package.json create mode 100644 src/scripts/tools/php-darwin/conf/platforms.json create mode 100644 src/scripts/tools/php-darwin/conf/versions create mode 100644 src/scripts/tools/php-darwin/scripts/existing-paths.sh create mode 100644 src/scripts/tools/php-darwin/scripts/extract.sh create mode 100644 src/scripts/tools/php-darwin/scripts/install.sh create mode 100644 src/scripts/tools/php-darwin/scripts/lib.sh create mode 100644 src/scripts/tools/php-darwin/scripts/registry.sh create mode 100644 src/scripts/tools/php-darwin/scripts/source-hash.sh create mode 100644 src/scripts/tools/php-darwin/templates/oci-descriptor.json diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index 7911a276..051bcc82 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -254,6 +254,27 @@ describe('Utils tests', () => { ); }); + it('builds the run-script path from only the script filename', () => { + const scriptPath = path.join( + '/tmp', + 'feature', + 'php-darwin-cache', + 'src', + 'scripts', + 'darwin.sh' + ); + expect(utils.scriptRunPath(scriptPath)).toBe( + path.join( + '/tmp', + 'feature', + 'php-darwin-cache', + 'src', + 'scripts', + 'run.sh' + ) + ); + }); + it('checking scriptTool', async () => { expect(await utils.scriptTool('linux')).toBe('bash '); expect(await utils.scriptTool('darwin')).toBe('bash '); diff --git a/dist/index.js b/dist/index.js index bcee2aa2..c67c45a0 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1 +1 @@ -(()=>{var e={472:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;io.escapeForShell(e,"linux")).join("\n")+'" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1'+r}async function addINIValuesWindows(e){const t=await o.CSVArray(e);let r="\n";await o.asyncForEach(t,async function(e){r+=await o.addLog("$tick",e,"Added to php.ini","win32")+"\n"});return'Add-Content "$php_dir\\php.ini" "'+t.map(e=>o.escapeForShell(e,"win32")).join("\n")+'"'+r}async function addINIValues(e,t,r=false){let n="\n";switch(r){case true:n+=await o.stepLog("Add php.ini values",t)+await o.suppressOutput(t)+"\n";break;case false:default:n+=await o.stepLog("Add php.ini values",t)+"\n";break}switch(t){case"win32":return n+await addINIValuesWindows(e);case"darwin":case"linux":return n+await addINIValuesUnix(e);default:return await o.log("Platform "+t+" is not supported",t,"error")}}},469:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:true});t.issueCommand=issueCommand;t.error=error;t.setFailed=setFailed;t.getInput=getInput;const n=r(857);function toCommandValue(e){if(e instanceof Error){return e.toString()}return e}function escapeData(e){return toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return e.replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}function issueCommand(e,t,r){let s=`::${e}`;if(t&&Object.keys(t).length>0){s+=" ";const e=Object.entries(t).filter(([,e])=>e).map(([e,t])=>`${e}=${escapeProperty(t)}`).join(",");s+=e}s+=`::${escapeData(r)}`;process.stdout.write(s+n.EOL)}function error(e){issueCommand("error",{},e)}function setFailed(e){process.exitCode=1;error(e)}function getInput(e,t=false){const r=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(t&&!r){throw new Error(`Input required and not supplied: ${e}`)}return r.trim()}},524:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i{"use strict";Object.defineProperty(t,"__esModule",{value:true});t.fetch=fetch;const r=new Set([301,302,303,307,308]);async function fetch(e,t,n=5){const s={"User-Agent":`Mozilla/5.0 (${process.platform} ${process.arch}) setup-php`};if(t){s["Authorization"]="Bearer "+t}try{const t=await globalThis.fetch(e,{headers:s,redirect:n>0?"follow":"manual"});if(t.ok){const e=await t.text();return{data:e}}else if(r.has(t.status)&&n<=0){return{error:`${t.status}: Redirect error`}}else{return{error:`${t.status}: ${t.statusText}`}}}catch(e){return{error:`Fetch error: ${e.message}`}}}},755:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i{await run()})().catch(e=>{l.setFailed(e.message)})},75:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;io.compareVersions(t.version,e.version));const s=r.find(e=>{if(e?.require?.php){return e?.require?.php.split("|").some(e=>e&&o.satisfies(t+".0",e))}return false});return s?s.version:null}return null}},159:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i or @sha512:"}}return{release:e}}e=e.slice(0,-t[0].length);const r=t[1].toLowerCase();if(!["sha256","sha512"].includes(r)){return{release:e,error:`Unsupported checksum algorithm ${r}, expected sha256 or sha512`}}const n=t[2].toLowerCase();const s=r==="sha256"?64:128;if(!new RegExp(`^[a-f0-9]{${s}}$`).test(n)){return{release:e,error:`Invalid ${r} checksum, expected ${s} hexadecimal characters`}}return{release:e,checksum:`${r}:${n}`}}function skipGitHubAuthForComposerVersion(e){if(!/^\d+\.\d+\.\d+(?:-[\w-]+)?$/.test(e)){return false}return c.default.readFileSync(a.default.join(__dirname,"../src/configs/composer-gh-auth-no-op"),"utf8").trim().split(/\r?\n/).some(t=>{const[r,n]=t.trim().split(/\s+/);return u.compareVersions(e,r)>=0&&u.compareVersions(e,n)<0})}function cleanComposerAuthJson(){try{const e=process.env["COMPOSER_AUTH_JSON"]||"";if(!e.includes("github-oauth"))return;const t=JSON.parse(e);delete t["github-oauth"];if(!Object.keys(t).length){delete process.env["COMPOSER_AUTH_JSON"]}else{process.env["COMPOSER_AUTH_JSON"]=JSON.stringify(t)}}catch{return}}async function getSemverVersion(e){const fixSemver=e=>{if(/^\d+\.\d+\.\d+(-|$)/.test(e))return e;const t=e.match(/^(\d+\.\d+\.\d+)([A-Za-z]+[0-9A-Za-z.]+)$/);return t?`${t[1]}-${t[2]}`:e};const t=e["version_prefix"]+e["version"];const r=`https://api.github.com/repos/${e["repository"]}/git/matching-refs/tags%2F${t}.`;const n=await f.readEnv("GITHUB_TOKEN")||await f.readEnv("COMPOSER_TOKEN");const s=await d.fetch(r,n);if(s.error||s.data==="[]"){e.error=s.error??`No version found with prefix ${t}.`;return e.version}else{const e=JSON.parse(s.data);const t=e.map(e=>(e.ref?.split("/").pop()??"").replace(/^v(?=\d)/,"")).filter(e=>e.length>0);const r=new Map;const n=t.map(e=>{const t=fixSemver(e);r.set(t,e);return t});const i=n.toSorted((e,t)=>{try{return u.compareVersions(t,e)}catch{return t.localeCompare(e,"en",{numeric:true,sensitivity:"base"})}});return r.get(i[0])??i[0]}}async function getLatestVersion(e){if(!e.version&&e.fetch_latest==="false"){return"latest"}if(e.fetch_latest==="true"&&!e.repository){return"latest"}const t=await d.fetch(`${e.github}/${e.repository}/releases.atom`);if(t.data){const e=[...t.data.matchAll(/releases\/tag\/([a-zA-Z]*)?(\d+\.\d+\.\d+)"/g)].map(e=>e[2]);const r=e.toSorted((e,t)=>e.localeCompare(t,undefined,{numeric:true}));return r.at(-1)||"latest"}return"latest"}async function getVersion(e,t){const r=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;const n=/^composer:(stable|preview|snapshot|[12])$/;const s=/[><=^~]+.*/;const i=/^\d+(\.\d+)?$/;t.version=e.replace(/v?(\d)/,"$1").replace(/\.x/,"");switch(true){case n.test(t.release):case r.test(t.version):case s.test(t.version)&&t.type==="composer":return t.version;case i.test(t.version)&&t.type==="composer":t.release=`${t.tool}:${t.version}.*`;return`${t.version}.*`;case!!t.repository&&i.test(t.version):return await getSemverVersion(t);default:return t.version.replace(/[^a-zA-Z0-9_.:@+,/-]/g,"")}}async function getRelease(e,t){e=e.includes("/")?e.split("/")[1]:e;return e.includes(":")?[t.tool,e.split(":")[1]].join(":"):t.tool}async function filterList(e){const t=/^composer($|:.*)/;const r=/^composer:?($|preview$|snapshot$|v?\d+(\.\d+)?$|v?\d+\.\d+\.\d+[\w-]*$)/;const n=e.filter(e=>r.test(extractChecksum(e).release));let s="composer";e=e.filter(e=>!t.test(extractChecksum(e).release));switch(true){case n[0]==undefined:break;default:s=n.at(-1).replace(/v(\d\S*)/,"$1");break}e.unshift(s);return e}async function getUrl(e){const t=e.version??"latest";if(t==="latest"||t===""){return[e.domain,e.repository,e.prefix,"latest",e.verb,e.tool+e.extension].filter(Boolean).join("/")}else{return[e.domain,e.repository,e.prefix,e.verb,e.version_prefix+e.version,e.tool+e.extension].filter(Boolean).join("/")}}async function getPharUrl(e){if(e.version==="latest"){return e.domain+"/"+e.tool+".phar"}else{return e.domain+"/"+e.tool+"-"+e.version_prefix+e.version+".phar"}}async function addArchive(e){return await f.getCommand(e.os,"tool")+await f.joins(e.url,e.tool,e.version_parameter)+(e.checksum?" "+e.checksum:"")}async function addPackage(e){const t=await f.getCommand(e.os,"composer_tool");const r=e.repository.split("/");const n=[r[1],e.release,r[0]+"/",e.scope].map(t=>f.safeArg(t,e.os)).join(" ");return t+n}async function addBlackfirePlayer(e){switch(e.os){case"win32":return await f.addLog("$cross",e.tool,e.tool+" is not a windows tool","win32");default:if(e.version=="latest"){if(/5\.[5-6]|7\.0/.test(e.php_version)){e.version="1.9.3"}else if(/7\.[1-4]|8\.0/.test(e.php_version)){e.version="1.22.0"}}e.url=await getPharUrl(e);return addArchive(e)}}async function addCastor(e){e.tool="castor."+e.os.replace("win32","windows")+"-amd64";e.url=await getUrl(e);e.tool="castor";e.version_parameter=c.default.existsSync("castor.php")?e.version_parameter:"";return await addArchive(e)}async function addComposer(e){const t=e.version.replace("latest","stable");const r=e.github;const n=e.domain;const s="https://dl.cloudsmith.io";const i="https://artifacts.setup-php.com";const o=`composer-${e.php_version}-${t}.phar`;const a=`${r}/shivammathur/composer-cache/releases/latest/download/${o}`;const c=`${s}/public/shivammathur/composer-cache/raw/files/${o}`;const u=`${i}/composer/${o}`;const d=`${n}/download/latest-2.2.x/composer.phar`;const l=/^5\.[3-6]$|^7\.[0-1]$/.test(e.php_version);const p=`${n}/composer-${t}.phar`;const h=`${n}/download/${t}/composer.phar`;let g=`${a},${u},${c}`;let w=`${n}/composer.phar`;let v="";switch(true){case/^snapshot$/.test(t):w=l?d:w;break;case/^preview$|^2$/.test(t):w=l?d:p;break;case/^1$/.test(t):w=p;break;case/^\d+\.\d+\.\d+(?:-[\w-]+)?$/.test(e.version):if(skipGitHubAuthForComposerVersion(e.version)){cleanComposerAuthJson();v=" true"}g=`${r}/${e.repository}/releases/download/${e.version}/composer.phar`;w=h;break;default:w=l?d:p}const m=await f.readEnv("NO_TOOLS_CACHE")!=="true";e.url=m?`${g},${w}`:w;e.version_parameter=e.version+v;return await addArchive(e)}async function addDeployer(e){if(e.version==="latest"){e.url=e.domain+"/deployer.phar"}else{const t=await d.fetch("https://deployer.org/manifest.json");const r=JSON.parse(t.data);const n=Object.keys(r).find(t=>r[t].version===e.version);if(n){e.url=r[n].url}else{return await f.addLog("$cross","deployer","Version missing in deployer manifest",e.os)}}return await addArchive(e)}async function addDevTools(e){switch(e.os){case"linux":case"darwin":return"add_devtools "+e.tool;case"win32":return await f.addLog("$tick",e.tool,e.tool+" is not a windows tool","win32");default:return await f.log("Platform "+e.os+" is not supported",e.os,"error")}}async function addPECL(e){return await f.getCommand(e.os,"pecl")}async function addPhing(e){e.url=e.domain+"/get/phing-"+e.version+e.extension;if(e.version!="latest"){[e.prefix,e.verb]=["releases","download"];e.domain=e.github;e.extension="-"+e.version+e.extension;e.url+=","+await getUrl(e)}return await addArchive(e)}async function addPhive(e){switch(true){case/5\.[3-5]/.test(e.php_version):return await f.addLog("$cross","phive","Phive is not supported on PHP "+e.php_version,e.os);case/5\.6|7\.0/.test(e.php_version):e.version="0.12.1";break;case/7\.1/.test(e.php_version):e.version="0.13.5";break;case/7\.2/.test(e.php_version):e.version="0.14.5";break;case/7\.3|7\.4/.test(e.php_version):e.version="0.15.3";break;case/^latest$/.test(e.version):e.version=await getLatestVersion(e);break}e.extension="-"+e.version+e.extension;e.url=await getUrl(e);return await addArchive(e)}async function addPHPUnitTools(e){if(e.version==="latest"){e.version=await l.search(e.packagist,e.php_version)??"latest"}e.url=await getPharUrl(e);if(e.url.match(/-\d+/)){e.url+=","+e.url.replace(/-(\d+)\.\d+\.\d+/,"-$1")}return await addArchive(e)}async function addWPCLI(e){if(e.version==="latest"){e.uri="wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true";e.url=[e.domain,e.uri].join("/")}else{e.extension="-"+e.version+e.extension;e.url=await getUrl(e)}return await addArchive(e)}async function getData(e,t,r){const n=a.default.join(__dirname,"../src/configs/tools.json");const s=c.default.readFileSync(n,"utf8");const i=JSON.parse(s);e=e.replace(/\s+/g,"");const o=extractChecksum(e);e=o.release;const u=e.split(":");const d=u[0];const l=u[1];let f;if(Object.hasOwn(i,d)){f={...i[d],tool:d}}else{const e=Object.keys(i).find(e=>i[e].alias==d);if(e){f={...i[e],tool:e}}else if(d.includes("/")){f={tool:d.split("/")[1],repository:d,type:"composer"}}else{f={tool:d}}}const p="https://github.com";const h=f.domain??p;const g={tool:f.tool,version:"",url:"",os:r,php_version:t,github:p,domain:h,extension:f.extension??".phar",repository:f.repository??"",prefix:h===p?"releases":"",verb:h===p?"download":"",fetch_latest:f.fetch_latest??"false",scope:f.scope??"global",version_parameter:f.version_parameter!=null?JSON.stringify(f.version_parameter):"",version_prefix:f.version_prefix??"",release:"",packagist:f.packagist??f.repository??"",type:f.type,function:f.function,alias:f.alias};g.checksum=o.checksum;g.error=o.error;g.release=await getRelease(e,g);g.version=l?await getVersion(l,g):await getLatestVersion(g);g.url=await getUrl(g);return g}t.functionRecord={castor:addCastor,composer:addComposer,deployer:addDeployer,dev_tools:addDevTools,phive:addPhive,blackfire_player:addBlackfirePlayer,pecl:addPECL,phing:addPhing,phpunit:addPHPUnitTools,phpcpd:addPHPUnitTools,wp_cli:addWPCLI};async function supportsChecksum(e){switch(e.type){case"phar":return true;case"custom-function":return!["pecl","dev_tools"].includes(e.function??"");default:return false}}async function addTools(e,r,n){let s="\n";if(e==="none"){return""}else{s+=await f.stepLog("Setup Tools",n)}const i=await filterList(await f.CSVArray(e));await f.asyncForEach(i,async function(e){const i=await getData(e,r,n);s+="\n";switch(true){case i.error!==undefined:s+=await f.addLog("$cross",i.tool,i.error,i.os);break;case i.checksum!==undefined&&!await supportsChecksum(i):s+=await f.addLog("$cross",i.tool,"Checksum verification is not supported for "+i.tool,i.os);break;case"phar"===i.type:s+=await addArchive(i);break;case"composer"===i.type:s+=await addPackage(i);break;case"custom-package"===i.type:s+=await f.customPackage(i.tool.split("-")[0],"tools",i.version,i.os);break;case"custom-function"===i.type:if(!i.function){s+=await f.addLog("$cross",i.tool,i.tool+" has no function defined. Please report this issue.",i.os)}else{s+=await t.functionRecord[i.function](i)}break;case/^none$/.test(i.tool):break;default:s+=await f.addLog("$cross",i.tool,"Tool "+i.tool+" is not supported",i.os);break}});return s}},277:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;ir.indexOf(e)===t);return n.map(e=>process.env[e]||"").find(Boolean)||""}async function getInput(e,t){const r=u.getInput(e);const n=await readEnv(e);switch(true){case r!="":return r;case r==""&&n!="":return n;case r==""&&n==""&&t:throw new Error(`Input required and not supplied: ${e}`);default:return""}}async function getManifestURLS(){return["https://raw.githubusercontent.com/shivammathur/setup-php/develop/src/configs/php-versions.json","https://setup-php.com/php-versions.json"]}async function parseVersion(e){switch(true){case/^pre(-installed)?$/.test(e):return"pre";case/^(latest|lowest|highest|nightly|master|\d+\.x)$/.test(e):for(const t of await getManifestURLS()){const r=await d.fetch(t);if(r["data"]??false){const t=JSON.parse(r["data"])[e];if(t===undefined){throw new Error(`Invalid PHP version: ${e.slice(0,20)}`)}if(!/^\d+\.\d+$/.test(t)){throw new Error(`Invalid PHP version in manifest: ${t.slice(0,10)}`)}return t}}throw new Error(`Could not fetch the PHP version manifest.`);default:if(!/^\d+(\.\d+){0,2}$/.test(e)){throw new Error(`Invalid PHP version: ${e.slice(0,20)}`)}switch(true){case e.length>1:return e.slice(0,3);default:return e+".0"}}}async function parseIniFile(e){if(/^(production|development|none)$/.test(e)){return e}const t=e.match(/php\.ini-(production|development)$/);return t?t[1]:"production"}async function asyncForEach(e,t){for(const[r,n]of e.entries()){await t(n,r,e)}}async function color(e){switch(e){case"error":return"31";default:case"success":return"32";case"warning":return"33"}}async function log(e,t,r){switch(t){case"win32":return'printf "\\033['+await color(r)+";1m"+e+' \\033[0m"';case"linux":case"darwin":default:return'echo "\\033['+await color(r)+";1m"+e+'\\033[0m"'}}async function stepLog(e,t){switch(t){case"win32":return'Step-Log "'+escapeForShell(e,t)+'"';case"linux":case"darwin":return'step_log "'+escapeForShell(e,t)+'"';default:return await log("Platform "+t+" is not supported",t,"error")}}async function addLog(e,t,r,n){const s=escapeForShell(t,n);const i=escapeForShell(r,n);switch(n){case"win32":return`Add-Log "${e}" "${s}" "${i}"`;case"linux":case"darwin":return`add_log "${e}" "${s}" "${i}"`;default:return await log("Platform "+n+" is not supported",n,"error")}}function escapeForShell(e,t){if(t==="win32"){return e.replace(/[`$"]/g,"`$&")}return e.replace(/[\\`$"]/g,"\\$&")}function safeArg(e,t){if(!/^[a-zA-Z0-9_./:@+,~^-]*$/.test(e)){return'"'+escapeForShell(e,t)+'"'}return e}function sanitizeShellInput(e,t=false){const r=t?/[$`"';|&(){}[\]\\<>*?\n\r\t]/g:/[$`"';|&(){}[\]\\\n\r\t]/g;return e.replace(r,"")}async function extensionArray(e){switch(e){case"":case" ":return[];default:return[e.match(/(^|,\s?)none(\s?,|$)/)?"none":"",...e.split(",").map(function(e){e=e.trim().replace(/^\\\s*/,"");if(/.+-.+\/.+@.+/.test(e)){return e}return e.toLowerCase().replace(/^(:)?(php[-_]|none|zend )|(-[^-]*)-/,"$1$3")})].filter(Boolean)}}async function CSVArray(e){switch(e){case"":case" ":return[];default:return e.split(/,(?=(?:(?:[^"']*["']){2})*[^"']*$)/).map(function(e){return e.trim().replace(/^["']|["']$|(?<==)["']/g,"").replace(/=(((?!E_).)*[?{}|&~![()^]+((?!E_).)+)/,"='$1'").replace(/=(.*?)(=.*)/,"='$1$2'").replace(/:\s*["'](.*?)/g,":$1")}).filter(Boolean)}}async function getExtensionPrefix(e){switch(true){default:return"extension";case/xdebug([2-3])?$|opcache|ioncube|eaccelerator/.test(e):return"zend_extension"}}async function suppressOutput(e){switch(e){case"win32":return" >$null 2>&1";case"linux":case"darwin":return" >/dev/null 2>&1";default:return await log("Platform "+e+" is not supported",e,"error")}}async function getUnsupportedLog(e,t,r){return"\n"+await addLog("$cross",e,[e,"is not supported on PHP",t].join(" "),r)+"\n"}async function getCommand(e,t){switch(e){case"linux":case"darwin":return"add_"+t+" ";case"win32":return"Add-"+t.split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("")+" ";default:return await log("Platform "+e+" is not supported",e,"error")}}async function joins(...e){return[...e].join(" ")}async function scriptExtension(e){switch(e){case"win32":return".ps1";case"linux":case"darwin":return".sh";default:return await log("Platform "+e+" is not supported",e,"error")}}async function scriptTool(e){switch(e){case"win32":return"pwsh ";case"linux":case"darwin":return"bash ";default:return await log("Platform "+e+" is not supported",e,"error")}}async function customPackage(e,t,r,n){const s=e.replace(/\d+|(pdo|pecl)[_-]|[_-]db2/,"");const i=await scriptExtension(n);const o=c.join(__dirname,"../src/scripts/"+t+"/"+s+i);const a=await getCommand(n,s);return"\n. "+o+"\n"+a+r}async function parseExtensionSource(e,t){const r=/(\w+)-(\w+:\/\/.{1,253}(?:[.:][^:/\s]{2,63})+\/)?([\w.-]+)\/([\w.-]+)@(.+)/;const n=r.exec(e);n[2]=n[2]?n[2].slice(0,-1):"https://github.com";return await joins("\nadd_extension_from_source",...n.splice(1,n.length),t)}const l=/^(latest|lowest|highest|nightly|master|pre|pre-installed|\d+\.x|\d+(\.\d+){0,2})$/;function validatePHPVersionInput(e,t){if(!l.test(e)){throw new Error(`Invalid PHP version in ${t}: ${e.slice(0,20)}`)}return e}async function readPHPVersion(){const e=await getInput("php-version",false);if(e){return validatePHPVersionInput(e,"php-version input")}const t=await getInput("php-version-file",false)||".php-version";if(a.default.existsSync(t)){const e=a.default.readFileSync(t,"utf8");const r=e.match(/^(?:php\s)?(\d+\.\d+\.\d+)$/m);return validatePHPVersionInput(r?r[1]:e.trim(),t)}else if(t!==".php-version"){throw new Error(`Could not find '${t}' file.`)}const r=await readEnv("COMPOSER_PROJECT_DIR");const n=c.join(r,"composer.lock");if(a.default.existsSync(n)){const e=JSON.parse(a.default.readFileSync(n,"utf8"));if(e["platform-overrides"]?.["php"]){return validatePHPVersionInput(e["platform-overrides"]["php"],"composer.lock platform-overrides.php")}}const s=c.join(r,"composer.json");if(a.default.existsSync(s)){const e=JSON.parse(a.default.readFileSync(s,"utf8"));if(e["config"]?.["platform"]?.["php"]){return validatePHPVersionInput(e["config"]["platform"]["php"],"composer.json config.platform.php")}}return"latest"}async function setVariable(e,t,r){switch(r){case"win32":return"\n$"+e+" = "+t+"\n";case"linux":case"darwin":default:return"\n"+e+'="$('+t+')"\n'}}},236:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i{o+=u.write(e);if(l){l(e)}};const stdOutListener=e=>{i+=c.write(e);if(d){d(e)}};const f=Object.assign(Object.assign({},r===null||r===void 0?void 0:r.listeners),{stdout:stdOutListener,stderr:stdErrListener});const p=yield exec(e,t,Object.assign(Object.assign({},r),{listeners:f}));i+=c.end();o+=u.end();return{exitCode:p,stdout:i,stderr:o}})}},665:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i-1){const e=n.substring(0,s);r(e);n=n.substring(s+a.EOL.length);s=n.indexOf(a.EOL)}return n}catch(e){this._debug(`error processing line. Failed with error ${e}`);return""}}_getSpawnFileName(){if(h){if(this._isCmdFile()){return process.env["COMSPEC"]||"cmd.exe"}}return this.toolPath}_getSpawnArgs(e){if(h){if(this._isCmdFile()){let t=`/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`;for(const r of this.args){t+=" ";t+=e.windowsVerbatimArguments?r:this._windowsQuoteCmdArg(r)}t+='"';return[t]}}return this.args}_endsWith(e,t){return e.endsWith(t)}_isCmdFile(){const e=this.toolPath.toUpperCase();return this._endsWith(e,".CMD")||this._endsWith(e,".BAT")}_windowsQuoteCmdArg(e){if(!this._isCmdFile()){return this._uvQuoteCmdArg(e)}if(!e){return'""'}const t=[" ","\t","&","(",")","[","]","{","}","^","=",";","!","'","+",",","`","~","|","<",">",'"'];let r=false;for(const n of e){if(t.some(e=>e===n)){r=true;break}}if(!r){return e}let n='"';let s=true;for(let t=e.length;t>0;t--){n+=e[t-1];if(s&&e[t-1]==="\\"){n+="\\"}else if(e[t-1]==='"'){s=true;n+='"'}else{s=false}}n+='"';return n.split("").reverse().join("")}_uvQuoteCmdArg(e){if(!e){return'""'}if(!e.includes(" ")&&!e.includes("\t")&&!e.includes('"')){return e}if(!e.includes('"')&&!e.includes("\\")){return`"${e}"`}let t='"';let r=true;for(let n=e.length;n>0;n--){t+=e[n-1];if(r&&e[n-1]==="\\"){t+="\\"}else if(e[n-1]==='"'){r=true;t+="\\"}else{r=false}}t+='"';return t.split("").reverse().join("")}_cloneExecOptions(e){e=e||{};const t={cwd:e.cwd||process.cwd(),env:e.env||process.env,silent:e.silent||false,windowsVerbatimArguments:e.windowsVerbatimArguments||false,failOnStdErr:e.failOnStdErr||false,ignoreReturnCode:e.ignoreReturnCode||false,delay:e.delay||1e4};t.outStream=e.outStream||process.stdout;t.errStream=e.errStream||process.stderr;return t}_getSpawnOptions(e,t){e=e||{};const r={};r.cwd=e.cwd;r.env=e.env;r["windowsVerbatimArguments"]=e.windowsVerbatimArguments||this._isCmdFile();if(e.windowsVerbatimArguments){r.argv0=`"${t}"`}return r}exec(){return o(this,void 0,void 0,function*(){if(!f.isRooted(this.toolPath)&&(this.toolPath.includes("/")||h&&this.toolPath.includes("\\"))){this.toolPath=d.resolve(process.cwd(),this.options.cwd||process.cwd(),this.toolPath)}this.toolPath=yield l.which(this.toolPath,true);return new Promise((e,t)=>o(this,void 0,void 0,function*(){this._debug(`exec tool: ${this.toolPath}`);this._debug("arguments:");for(const e of this.args){this._debug(` ${e}`)}const r=this._cloneExecOptions(this.options);if(!r.silent&&r.outStream){r.outStream.write(this._getCommandString(r)+a.EOL)}const n=new ExecState(r,this.toolPath);n.on("debug",e=>{this._debug(e)});if(this.options.cwd&&!(yield f.exists(this.options.cwd))){return t(new Error(`The cwd: ${this.options.cwd} does not exist!`))}const s=this._getSpawnFileName();const i=u.spawn(s,this._getSpawnArgs(r),this._getSpawnOptions(this.options,s));let o="";if(i.stdout){i.stdout.on("data",e=>{if(this.options.listeners&&this.options.listeners.stdout){this.options.listeners.stdout(e)}if(!r.silent&&r.outStream){r.outStream.write(e)}o=this._processLineBuffer(e,o,e=>{if(this.options.listeners&&this.options.listeners.stdline){this.options.listeners.stdline(e)}})})}let c="";if(i.stderr){i.stderr.on("data",e=>{n.processStderr=true;if(this.options.listeners&&this.options.listeners.stderr){this.options.listeners.stderr(e)}if(!r.silent&&r.errStream&&r.outStream){const t=r.failOnStdErr?r.errStream:r.outStream;t.write(e)}c=this._processLineBuffer(e,c,e=>{if(this.options.listeners&&this.options.listeners.errline){this.options.listeners.errline(e)}})})}i.on("error",e=>{n.processError=e.message;n.processExited=true;n.processClosed=true;n.CheckComplete()});i.on("exit",e=>{n.processExitCode=e;n.processExited=true;this._debug(`Exit code ${e} received from tool '${this.toolPath}'`);n.CheckComplete()});i.on("close",e=>{n.processExitCode=e;n.processExited=true;n.processClosed=true;this._debug(`STDIO streams have closed for tool '${this.toolPath}'`);n.CheckComplete()});n.on("done",(r,n)=>{if(o.length>0){this.emit("stdline",o)}if(c.length>0){this.emit("errline",c)}i.removeAllListeners();if(r){t(r)}else{e(n)}});if(this.options.input){if(!i.stdin){throw new Error("child process missing stdin")}i.stdin.end(this.options.input)}}))})}}t.ToolRunner=ToolRunner;function argStringToArray(e){const t=[];let r=false;let n=false;let s="";function append(e){if(n&&e!=='"'){s+="\\"}s+=e;n=false}for(let i=0;i0){t.push(s);s=""}continue}append(o)}if(s.length>0){t.push(s.trim())}return t}class ExecState extends c.EventEmitter{constructor(e,t){super();this.processClosed=false;this.processError="";this.processExitCode=0;this.processExited=false;this.processStderr=false;this.delay=1e4;this.done=false;this.timeout=null;if(!t){throw new Error("toolPath must not be empty")}this.options=e;this.toolPath=t;if(e.delay){this.delay=e.delay}}CheckComplete(){if(this.done){return}if(this.processClosed){this._setResult()}else if(this.processExited){this.timeout=(0,p.setTimeout)(ExecState.HandleTimeout,this.delay,this)}}_debug(e){this.emit("debug",e)}_setResult(){let e;if(this.processExited){if(this.processError){e=new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`)}else if(this.processExitCode!==0&&!this.options.ignoreReturnCode){e=new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`)}else if(this.processStderr&&this.options.failOnStdErr){e=new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`)}}if(this.timeout){clearTimeout(this.timeout);this.timeout=null}this.done=true;this.emit("done",e,this.processExitCode)}static HandleTimeout(e){if(e.done){return}if(!e.processClosed&&e.processExited){const t=`The STDIO streams did not close within ${e.delay/1e3} seconds of the exit event from process '${e.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`;e._debug(t)}e._setResult()}}},207:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;ie.toUpperCase()===t)){return e}}else{if(isUnixExecutable(n)){return e}}}const s=e;for(const i of r){e=s+i;n=undefined;try{n=yield(0,t.stat)(e)}catch(t){if(t.code!=="ENOENT"){console.log(`Unexpected error attempting to determine if executable file exists '${e}': ${t}`)}}if(n&&n.isFile()){if(t.IS_WINDOWS){try{const r=u.dirname(e);const n=u.basename(e).toUpperCase();for(const s of yield(0,t.readdir)(r)){if(n===s.toUpperCase()){e=u.join(r,s);break}}}catch(t){console.log(`Unexpected error attempting to determine the actual case of the file '${e}': ${t}`)}return e}else{if(isUnixExecutable(n)){return e}}}}return""})}function normalizeSeparators(e){e=e||"";if(t.IS_WINDOWS){e=e.replace(/\//g,"\\");return e.replace(/\\\\+/g,"\\")}return e.replace(/\/\/+/g,"/")}function isUnixExecutable(e){return(e.mode&1)>0||(e.mode&8)>0&&process.getgid!==undefined&&e.gid===process.getgid()||(e.mode&64)>0&&process.getuid!==undefined&&e.uid===process.getuid()}function getCmdPath(){var e;return(e=process.env["COMSPEC"])!==null&&e!==void 0?e:`cmd.exe`}},994:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i|]/.test(e)){throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows')}}try{yield u.rm(e,{force:true,maxRetries:3,recursive:true,retryDelay:300})}catch(e){throw new Error(`File was unable to be removed ${e}`)}})}function mkdirP(e){return o(this,void 0,void 0,function*(){(0,a.ok)(e,"a path argument must be provided");yield u.mkdir(e,{recursive:true})})}function which(e,t){return o(this,void 0,void 0,function*(){if(!e){throw new Error("parameter 'tool' is required")}if(t){const t=yield which(e,false);if(!t){if(u.IS_WINDOWS){throw new Error(`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`)}else{throw new Error(`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`)}}return t}const r=yield findInPath(e);if(r&&r.length>0){return r[0]}return""})}function findInPath(e){return o(this,void 0,void 0,function*(){if(!e){throw new Error("parameter 'tool' is required")}const t=[];if(u.IS_WINDOWS&&process.env["PATHEXT"]){for(const e of process.env["PATHEXT"].split(c.delimiter)){if(e){t.push(e)}}}if(u.isRooted(e)){const r=yield u.tryGetExecutablePath(e,t);if(r){return[r]}return[]}if(e.includes(c.sep)){return[]}const r=[];if(process.env.PATH){for(const e of process.env.PATH.split(c.delimiter)){if(e){r.push(e)}}}const n=[];for(const s of r){const r=yield u.tryGetExecutablePath(c.join(s,e),t);if(r){n.push(r)}}return n})}function readCopyOptions(e){const t=e.force==null?true:e.force;const r=Boolean(e.recursive);const n=e.copySourceDirectory==null?true:Boolean(e.copySourceDirectory);return{force:t,recursive:r,copySourceDirectory:n}}function cpDirRecursive(e,t,r,n){return o(this,void 0,void 0,function*(){if(r>=255)return;r++;yield mkdirP(t);const s=yield u.readdir(e);for(const i of s){const s=`${e}/${i}`;const o=`${t}/${i}`;const a=yield u.lstat(s);if(a.isDirectory()){yield cpDirRecursive(s,o,r,n)}else{yield copyFile(s,o,n)}}yield u.chmod(t,(yield u.stat(e)).mode)})}function copyFile(e,t,r){return o(this,void 0,void 0,function*(){if((yield u.lstat(e)).isSymbolicLink()){try{yield u.lstat(t);yield u.unlink(t)}catch(e){if(e.code==="EPERM"){yield u.chmod(t,"0666");yield u.unlink(t)}}const r=yield u.readlink(e);yield u.symlink(r,t,u.IS_WINDOWS?"junction":null)}else if(!(yield u.exists(t))||r){yield u.copyFile(e,t)}})}},26:function(e,t){(function(e,r){true?r(t):0})(this,function(e){"use strict";const t=/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;const validateAndParse=e=>{if(typeof e!=="string"){throw new TypeError("Invalid argument expected string")}const r=e.match(t);if(!r){throw new Error(`Invalid argument not valid semver ('${e}' received)`)}r.shift();return r};const isWildcard=e=>e==="*"||e==="x"||e==="X";const tryParse=e=>{const t=parseInt(e,10);return isNaN(t)?e:t};const forceType=(e,t)=>typeof e!==typeof t?[String(e),String(t)]:[e,t];const compareStrings=(e,t)=>{if(isWildcard(e)||isWildcard(t))return 0;const[r,n]=forceType(tryParse(e),tryParse(t));if(r>n)return 1;if(r{for(let r=0;r{const r=validateAndParse(e);const n=validateAndParse(t);const s=r.pop();const i=n.pop();const o=compareSegments(r,n);if(o!==0)return o;if(s&&i){return compareSegments(s.split("."),i.split("."))}else if(s||i){return s?-1:1}return 0};const compare=(e,t,n)=>{assertValidOperator(n);const s=compareVersions(e,t);return r[n].includes(s)};const r={">":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1],"!=":[-1,1]};const n=Object.keys(r);const assertValidOperator=e=>{if(typeof e!=="string"){throw new TypeError(`Invalid operator type, expected string but got ${typeof e}`)}if(n.indexOf(e)===-1){throw new Error(`Invalid operator, expected one of ${n.join("|")}`)}};const satisfies=(e,t)=>{t=t.replace(/([><=]+)\s+/g,"$1");if(t.includes("||")){return t.split("||").some(t=>satisfies(e,t))}else if(t.includes(" - ")){const[r,n]=t.split(" - ",2);return satisfies(e,`>=${r} <=${n}`)}else if(t.includes(" ")){return t.trim().replace(/\s{2,}/g," ").split(" ").every(t=>satisfies(e,t))}const r=t.match(/^([<>=~^]+)/);const n=r?r[1]:"=";if(n!=="^"&&n!=="~")return compare(e,t,n);const[s,i,o,,a]=validateAndParse(e);const[c,u,d,,l]=validateAndParse(t);const f=[s,i,o];const p=[c,u!==null&&u!==void 0?u:"x",d!==null&&d!==void 0?d:"x"];if(l){if(!a)return false;if(compareSegments(f,p)!==0)return false;if(compareSegments(a.split("."),l.split("."))===-1)return false}const h=p.findIndex(e=>e!=="0")+1;const g=n==="~"?2:h>1?h:1;if(compareSegments(f.slice(0,g),p.slice(0,g))!==0)return false;if(compareSegments(f.slice(g),p.slice(g))===-1)return false;return true};const validate=e=>typeof e==="string"&&/^[v\d]/.test(e)&&t.test(e);const validateStrict=e=>typeof e==="string"&&/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(e);e.compare=compare;e.compareVersions=compareVersions;e.satisfies=satisfies;e.validate=validate;e.validateStrict=validateStrict})},613:e=>{"use strict";e.exports=require("assert")},317:e=>{"use strict";e.exports=require("child_process")},434:e=>{"use strict";e.exports=require("events")},896:e=>{"use strict";e.exports=require("fs")},857:e=>{"use strict";e.exports=require("os")},928:e=>{"use strict";e.exports=require("path")},193:e=>{"use strict";e.exports=require("string_decoder")},557:e=>{"use strict";e.exports=require("timers")}};var t={};function __nccwpck_require__(r){var n=t[r];if(n!==undefined){return n.exports}var s=t[r]={exports:{}};var i=true;try{e[r].call(s.exports,s,s.exports,__nccwpck_require__);i=false}finally{if(i)delete t[r]}return s.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(755);module.exports=r})(); \ No newline at end of file +(()=>{var e={472:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;io.escapeForShell(e,"linux")).join("\n")+'" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1'+r}async function addINIValuesWindows(e){const t=await o.CSVArray(e);let r="\n";await o.asyncForEach(t,async function(e){r+=await o.addLog("$tick",e,"Added to php.ini","win32")+"\n"});return'Add-Content "$php_dir\\php.ini" "'+t.map(e=>o.escapeForShell(e,"win32")).join("\n")+'"'+r}async function addINIValues(e,t,r=false){let n="\n";switch(r){case true:n+=await o.stepLog("Add php.ini values",t)+await o.suppressOutput(t)+"\n";break;case false:default:n+=await o.stepLog("Add php.ini values",t)+"\n";break}switch(t){case"win32":return n+await addINIValuesWindows(e);case"darwin":case"linux":return n+await addINIValuesUnix(e);default:return await o.log("Platform "+t+" is not supported",t,"error")}}},469:(e,t,r)=>{"use strict";Object.defineProperty(t,"__esModule",{value:true});t.issueCommand=issueCommand;t.error=error;t.setFailed=setFailed;t.getInput=getInput;const n=r(857);function toCommandValue(e){if(e instanceof Error){return e.toString()}return e}function escapeData(e){return toCommandValue(e).replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function escapeProperty(e){return e.replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A").replace(/:/g,"%3A").replace(/,/g,"%2C")}function issueCommand(e,t,r){let s=`::${e}`;if(t&&Object.keys(t).length>0){s+=" ";const e=Object.entries(t).filter(([,e])=>e).map(([e,t])=>`${e}=${escapeProperty(t)}`).join(",");s+=e}s+=`::${escapeData(r)}`;process.stdout.write(s+n.EOL)}function error(e){issueCommand("error",{},e)}function setFailed(e){process.exitCode=1;error(e)}function getInput(e,t=false){const r=process.env[`INPUT_${e.replace(/ /g,"_").toUpperCase()}`]||"";if(t&&!r){throw new Error(`Input required and not supplied: ${e}`)}return r.trim()}},524:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i{"use strict";Object.defineProperty(t,"__esModule",{value:true});t.fetch=fetch;const r=new Set([301,302,303,307,308]);async function fetch(e,t,n=5){const s={"User-Agent":`Mozilla/5.0 (${process.platform} ${process.arch}) setup-php`};if(t){s["Authorization"]="Bearer "+t}try{const t=await globalThis.fetch(e,{headers:s,redirect:n>0?"follow":"manual"});if(t.ok){const e=await t.text();return{data:e}}else if(r.has(t.status)&&n<=0){return{error:`${t.status}: Redirect error`}}else{return{error:`${t.status}: ${t.statusText}`}}}catch(e){return{error:`Fetch error: ${e.message}`}}}},755:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i{await run()})().catch(e=>{l.setFailed(e.message)})},75:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;io.compareVersions(t.version,e.version));const s=r.find(e=>{if(e?.require?.php){return e?.require?.php.split("|").some(e=>e&&o.satisfies(t+".0",e))}return false});return s?s.version:null}return null}},159:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i or @sha512:"}}return{release:e}}e=e.slice(0,-t[0].length);const r=t[1].toLowerCase();if(!["sha256","sha512"].includes(r)){return{release:e,error:`Unsupported checksum algorithm ${r}, expected sha256 or sha512`}}const n=t[2].toLowerCase();const s=r==="sha256"?64:128;if(!new RegExp(`^[a-f0-9]{${s}}$`).test(n)){return{release:e,error:`Invalid ${r} checksum, expected ${s} hexadecimal characters`}}return{release:e,checksum:`${r}:${n}`}}function skipGitHubAuthForComposerVersion(e){if(!/^\d+\.\d+\.\d+(?:-[\w-]+)?$/.test(e)){return false}return c.default.readFileSync(a.default.join(__dirname,"../src/configs/composer-gh-auth-no-op"),"utf8").trim().split(/\r?\n/).some(t=>{const[r,n]=t.trim().split(/\s+/);return u.compareVersions(e,r)>=0&&u.compareVersions(e,n)<0})}function cleanComposerAuthJson(){try{const e=process.env["COMPOSER_AUTH_JSON"]||"";if(!e.includes("github-oauth"))return;const t=JSON.parse(e);delete t["github-oauth"];if(!Object.keys(t).length){delete process.env["COMPOSER_AUTH_JSON"]}else{process.env["COMPOSER_AUTH_JSON"]=JSON.stringify(t)}}catch{return}}async function getSemverVersion(e){const fixSemver=e=>{if(/^\d+\.\d+\.\d+(-|$)/.test(e))return e;const t=e.match(/^(\d+\.\d+\.\d+)([A-Za-z]+[0-9A-Za-z.]+)$/);return t?`${t[1]}-${t[2]}`:e};const t=e["version_prefix"]+e["version"];const r=`https://api.github.com/repos/${e["repository"]}/git/matching-refs/tags%2F${t}.`;const n=await f.readEnv("GITHUB_TOKEN")||await f.readEnv("COMPOSER_TOKEN");const s=await d.fetch(r,n);if(s.error||s.data==="[]"){e.error=s.error??`No version found with prefix ${t}.`;return e.version}else{const e=JSON.parse(s.data);const t=e.map(e=>(e.ref?.split("/").pop()??"").replace(/^v(?=\d)/,"")).filter(e=>e.length>0);const r=new Map;const n=t.map(e=>{const t=fixSemver(e);r.set(t,e);return t});const i=n.toSorted((e,t)=>{try{return u.compareVersions(t,e)}catch{return t.localeCompare(e,"en",{numeric:true,sensitivity:"base"})}});return r.get(i[0])??i[0]}}async function getLatestVersion(e){if(!e.version&&e.fetch_latest==="false"){return"latest"}if(e.fetch_latest==="true"&&!e.repository){return"latest"}const t=await d.fetch(`${e.github}/${e.repository}/releases.atom`);if(t.data){const e=[...t.data.matchAll(/releases\/tag\/([a-zA-Z]*)?(\d+\.\d+\.\d+)"/g)].map(e=>e[2]);const r=e.toSorted((e,t)=>e.localeCompare(t,undefined,{numeric:true}));return r.at(-1)||"latest"}return"latest"}async function getVersion(e,t){const r=/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;const n=/^composer:(stable|preview|snapshot|[12])$/;const s=/[><=^~]+.*/;const i=/^\d+(\.\d+)?$/;t.version=e.replace(/v?(\d)/,"$1").replace(/\.x/,"");switch(true){case n.test(t.release):case r.test(t.version):case s.test(t.version)&&t.type==="composer":return t.version;case i.test(t.version)&&t.type==="composer":t.release=`${t.tool}:${t.version}.*`;return`${t.version}.*`;case!!t.repository&&i.test(t.version):return await getSemverVersion(t);default:return t.version.replace(/[^a-zA-Z0-9_.:@+,/-]/g,"")}}async function getRelease(e,t){e=e.includes("/")?e.split("/")[1]:e;return e.includes(":")?[t.tool,e.split(":")[1]].join(":"):t.tool}async function filterList(e){const t=/^composer($|:.*)/;const r=/^composer:?($|preview$|snapshot$|v?\d+(\.\d+)?$|v?\d+\.\d+\.\d+[\w-]*$)/;const n=e.filter(e=>r.test(extractChecksum(e).release));let s="composer";e=e.filter(e=>!t.test(extractChecksum(e).release));switch(true){case n[0]==undefined:break;default:s=n.at(-1).replace(/v(\d\S*)/,"$1");break}e.unshift(s);return e}async function getUrl(e){const t=e.version??"latest";if(t==="latest"||t===""){return[e.domain,e.repository,e.prefix,"latest",e.verb,e.tool+e.extension].filter(Boolean).join("/")}else{return[e.domain,e.repository,e.prefix,e.verb,e.version_prefix+e.version,e.tool+e.extension].filter(Boolean).join("/")}}async function getPharUrl(e){if(e.version==="latest"){return e.domain+"/"+e.tool+".phar"}else{return e.domain+"/"+e.tool+"-"+e.version_prefix+e.version+".phar"}}async function addArchive(e){return await f.getCommand(e.os,"tool")+await f.joins(e.url,e.tool,e.version_parameter)+(e.checksum?" "+e.checksum:"")}async function addPackage(e){const t=await f.getCommand(e.os,"composer_tool");const r=e.repository.split("/");const n=[r[1],e.release,r[0]+"/",e.scope].map(t=>f.safeArg(t,e.os)).join(" ");return t+n}async function addBlackfirePlayer(e){switch(e.os){case"win32":return await f.addLog("$cross",e.tool,e.tool+" is not a windows tool","win32");default:if(e.version=="latest"){if(/5\.[5-6]|7\.0/.test(e.php_version)){e.version="1.9.3"}else if(/7\.[1-4]|8\.0/.test(e.php_version)){e.version="1.22.0"}}e.url=await getPharUrl(e);return addArchive(e)}}async function addCastor(e){e.tool="castor."+e.os.replace("win32","windows")+"-amd64";e.url=await getUrl(e);e.tool="castor";e.version_parameter=c.default.existsSync("castor.php")?e.version_parameter:"";return await addArchive(e)}async function addComposer(e){const t=e.version.replace("latest","stable");const r=e.github;const n=e.domain;const s="https://dl.cloudsmith.io";const i="https://artifacts.setup-php.com";const o=`composer-${e.php_version}-${t}.phar`;const a=`${r}/shivammathur/composer-cache/releases/latest/download/${o}`;const c=`${s}/public/shivammathur/composer-cache/raw/files/${o}`;const u=`${i}/composer/${o}`;const d=`${n}/download/latest-2.2.x/composer.phar`;const l=/^5\.[3-6]$|^7\.[0-1]$/.test(e.php_version);const p=`${n}/composer-${t}.phar`;const h=`${n}/download/${t}/composer.phar`;let g=`${a},${u},${c}`;let w=`${n}/composer.phar`;let m="";switch(true){case/^snapshot$/.test(t):w=l?d:w;break;case/^preview$|^2$/.test(t):w=l?d:p;break;case/^1$/.test(t):w=p;break;case/^\d+\.\d+\.\d+(?:-[\w-]+)?$/.test(e.version):if(skipGitHubAuthForComposerVersion(e.version)){cleanComposerAuthJson();m=" true"}g=`${r}/${e.repository}/releases/download/${e.version}/composer.phar`;w=h;break;default:w=l?d:p}const v=await f.readEnv("NO_TOOLS_CACHE")!=="true";e.url=v?`${g},${w}`:w;e.version_parameter=e.version+m;return await addArchive(e)}async function addDeployer(e){if(e.version==="latest"){e.url=e.domain+"/deployer.phar"}else{const t=await d.fetch("https://deployer.org/manifest.json");const r=JSON.parse(t.data);const n=Object.keys(r).find(t=>r[t].version===e.version);if(n){e.url=r[n].url}else{return await f.addLog("$cross","deployer","Version missing in deployer manifest",e.os)}}return await addArchive(e)}async function addDevTools(e){switch(e.os){case"linux":case"darwin":return"add_devtools "+e.tool;case"win32":return await f.addLog("$tick",e.tool,e.tool+" is not a windows tool","win32");default:return await f.log("Platform "+e.os+" is not supported",e.os,"error")}}async function addPECL(e){return await f.getCommand(e.os,"pecl")}async function addPhing(e){e.url=e.domain+"/get/phing-"+e.version+e.extension;if(e.version!="latest"){[e.prefix,e.verb]=["releases","download"];e.domain=e.github;e.extension="-"+e.version+e.extension;e.url+=","+await getUrl(e)}return await addArchive(e)}async function addPhive(e){switch(true){case/5\.[3-5]/.test(e.php_version):return await f.addLog("$cross","phive","Phive is not supported on PHP "+e.php_version,e.os);case/5\.6|7\.0/.test(e.php_version):e.version="0.12.1";break;case/7\.1/.test(e.php_version):e.version="0.13.5";break;case/7\.2/.test(e.php_version):e.version="0.14.5";break;case/7\.3|7\.4/.test(e.php_version):e.version="0.15.3";break;case/^latest$/.test(e.version):e.version=await getLatestVersion(e);break}e.extension="-"+e.version+e.extension;e.url=await getUrl(e);return await addArchive(e)}async function addPHPUnitTools(e){if(e.version==="latest"){e.version=await l.search(e.packagist,e.php_version)??"latest"}e.url=await getPharUrl(e);if(e.url.match(/-\d+/)){e.url+=","+e.url.replace(/-(\d+)\.\d+\.\d+/,"-$1")}return await addArchive(e)}async function addWPCLI(e){if(e.version==="latest"){e.uri="wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true";e.url=[e.domain,e.uri].join("/")}else{e.extension="-"+e.version+e.extension;e.url=await getUrl(e)}return await addArchive(e)}async function getData(e,t,r){const n=a.default.join(__dirname,"../src/configs/tools.json");const s=c.default.readFileSync(n,"utf8");const i=JSON.parse(s);e=e.replace(/\s+/g,"");const o=extractChecksum(e);e=o.release;const u=e.split(":");const d=u[0];const l=u[1];let f;if(Object.hasOwn(i,d)){f={...i[d],tool:d}}else{const e=Object.keys(i).find(e=>i[e].alias==d);if(e){f={...i[e],tool:e}}else if(d.includes("/")){f={tool:d.split("/")[1],repository:d,type:"composer"}}else{f={tool:d}}}const p="https://github.com";const h=f.domain??p;const g={tool:f.tool,version:"",url:"",os:r,php_version:t,github:p,domain:h,extension:f.extension??".phar",repository:f.repository??"",prefix:h===p?"releases":"",verb:h===p?"download":"",fetch_latest:f.fetch_latest??"false",scope:f.scope??"global",version_parameter:f.version_parameter!=null?JSON.stringify(f.version_parameter):"",version_prefix:f.version_prefix??"",release:"",packagist:f.packagist??f.repository??"",type:f.type,function:f.function,alias:f.alias};g.checksum=o.checksum;g.error=o.error;g.release=await getRelease(e,g);g.version=l?await getVersion(l,g):await getLatestVersion(g);g.url=await getUrl(g);return g}t.functionRecord={castor:addCastor,composer:addComposer,deployer:addDeployer,dev_tools:addDevTools,phive:addPhive,blackfire_player:addBlackfirePlayer,pecl:addPECL,phing:addPhing,phpunit:addPHPUnitTools,phpcpd:addPHPUnitTools,wp_cli:addWPCLI};async function supportsChecksum(e){switch(e.type){case"phar":return true;case"custom-function":return!["pecl","dev_tools"].includes(e.function??"");default:return false}}async function addTools(e,r,n){let s="\n";if(e==="none"){return""}else{s+=await f.stepLog("Setup Tools",n)}const i=await filterList(await f.CSVArray(e));await f.asyncForEach(i,async function(e){const i=await getData(e,r,n);s+="\n";switch(true){case i.error!==undefined:s+=await f.addLog("$cross",i.tool,i.error,i.os);break;case i.checksum!==undefined&&!await supportsChecksum(i):s+=await f.addLog("$cross",i.tool,"Checksum verification is not supported for "+i.tool,i.os);break;case"phar"===i.type:s+=await addArchive(i);break;case"composer"===i.type:s+=await addPackage(i);break;case"custom-package"===i.type:s+=await f.customPackage(i.tool.split("-")[0],"tools",i.version,i.os);break;case"custom-function"===i.type:if(!i.function){s+=await f.addLog("$cross",i.tool,i.tool+" has no function defined. Please report this issue.",i.os)}else{s+=await t.functionRecord[i.function](i)}break;case/^none$/.test(i.tool):break;default:s+=await f.addLog("$cross",i.tool,"Tool "+i.tool+" is not supported",i.os);break}});return s}},277:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;ir.indexOf(e)===t);return n.map(e=>process.env[e]||"").find(Boolean)||""}async function getInput(e,t){const r=u.getInput(e);const n=await readEnv(e);switch(true){case r!="":return r;case r==""&&n!="":return n;case r==""&&n==""&&t:throw new Error(`Input required and not supplied: ${e}`);default:return""}}async function getManifestURLS(){return["https://raw.githubusercontent.com/shivammathur/setup-php/develop/src/configs/php-versions.json","https://setup-php.com/php-versions.json"]}async function parseVersion(e){switch(true){case/^pre(-installed)?$/.test(e):return"pre";case/^(latest|lowest|highest|nightly|master|\d+\.x)$/.test(e):for(const t of await getManifestURLS()){const r=await d.fetch(t);if(r["data"]??false){const t=JSON.parse(r["data"])[e];if(t===undefined){throw new Error(`Invalid PHP version: ${e.slice(0,20)}`)}if(!/^\d+\.\d+$/.test(t)){throw new Error(`Invalid PHP version in manifest: ${t.slice(0,10)}`)}return t}}throw new Error(`Could not fetch the PHP version manifest.`);default:if(!/^\d+(\.\d+){0,2}$/.test(e)){throw new Error(`Invalid PHP version: ${e.slice(0,20)}`)}switch(true){case e.length>1:return e.slice(0,3);default:return e+".0"}}}async function parseIniFile(e){if(/^(production|development|none)$/.test(e)){return e}const t=e.match(/php\.ini-(production|development)$/);return t?t[1]:"production"}async function asyncForEach(e,t){for(const[r,n]of e.entries()){await t(n,r,e)}}async function color(e){switch(e){case"error":return"31";default:case"success":return"32";case"warning":return"33"}}async function log(e,t,r){switch(t){case"win32":return'printf "\\033['+await color(r)+";1m"+e+' \\033[0m"';case"linux":case"darwin":default:return'echo "\\033['+await color(r)+";1m"+e+'\\033[0m"'}}async function stepLog(e,t){switch(t){case"win32":return'Step-Log "'+escapeForShell(e,t)+'"';case"linux":case"darwin":return'step_log "'+escapeForShell(e,t)+'"';default:return await log("Platform "+t+" is not supported",t,"error")}}async function addLog(e,t,r,n){const s=escapeForShell(t,n);const i=escapeForShell(r,n);switch(n){case"win32":return`Add-Log "${e}" "${s}" "${i}"`;case"linux":case"darwin":return`add_log "${e}" "${s}" "${i}"`;default:return await log("Platform "+n+" is not supported",n,"error")}}function escapeForShell(e,t){if(t==="win32"){return e.replace(/[`$"]/g,"`$&")}return e.replace(/[\\`$"]/g,"\\$&")}function safeArg(e,t){if(!/^[a-zA-Z0-9_./:@+,~^-]*$/.test(e)){return'"'+escapeForShell(e,t)+'"'}return e}function sanitizeShellInput(e,t=false){const r=t?/[$`"';|&(){}[\]\\<>*?\n\r\t]/g:/[$`"';|&(){}[\]\\\n\r\t]/g;return e.replace(r,"")}async function extensionArray(e){switch(e){case"":case" ":return[];default:return[e.match(/(^|,\s?)none(\s?,|$)/)?"none":"",...e.split(",").map(function(e){e=e.trim().replace(/^\\\s*/,"");if(/.+-.+\/.+@.+/.test(e)){return e}return e.toLowerCase().replace(/^(:)?(php[-_]|none|zend )|(-[^-]*)-/,"$1$3")})].filter(Boolean)}}async function CSVArray(e){switch(e){case"":case" ":return[];default:return e.split(/,(?=(?:(?:[^"']*["']){2})*[^"']*$)/).map(function(e){return e.trim().replace(/^["']|["']$|(?<==)["']/g,"").replace(/=(((?!E_).)*[?{}|&~![()^]+((?!E_).)+)/,"='$1'").replace(/=(.*?)(=.*)/,"='$1$2'").replace(/:\s*["'](.*?)/g,":$1")}).filter(Boolean)}}async function getExtensionPrefix(e){switch(true){default:return"extension";case/xdebug([2-3])?$|opcache|ioncube|eaccelerator/.test(e):return"zend_extension"}}async function suppressOutput(e){switch(e){case"win32":return" >$null 2>&1";case"linux":case"darwin":return" >/dev/null 2>&1";default:return await log("Platform "+e+" is not supported",e,"error")}}async function getUnsupportedLog(e,t,r){return"\n"+await addLog("$cross",e,[e,"is not supported on PHP",t].join(" "),r)+"\n"}async function getCommand(e,t){switch(e){case"linux":case"darwin":return"add_"+t+" ";case"win32":return"Add-"+t.split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("")+" ";default:return await log("Platform "+e+" is not supported",e,"error")}}async function joins(...e){return[...e].join(" ")}async function scriptExtension(e){switch(e){case"win32":return".ps1";case"linux":case"darwin":return".sh";default:return await log("Platform "+e+" is not supported",e,"error")}}function scriptRunPath(e){return c.join(c.dirname(e),`run${c.extname(e)}`)}async function scriptTool(e){switch(e){case"win32":return"pwsh ";case"linux":case"darwin":return"bash ";default:return await log("Platform "+e+" is not supported",e,"error")}}async function customPackage(e,t,r,n){const s=e.replace(/\d+|(pdo|pecl)[_-]|[_-]db2/,"");const i=await scriptExtension(n);const o=c.join(__dirname,"../src/scripts/"+t+"/"+s+i);const a=await getCommand(n,s);return"\n. "+o+"\n"+a+r}async function parseExtensionSource(e,t){const r=/(\w+)-(\w+:\/\/.{1,253}(?:[.:][^:/\s]{2,63})+\/)?([\w.-]+)\/([\w.-]+)@(.+)/;const n=r.exec(e);n[2]=n[2]?n[2].slice(0,-1):"https://github.com";return await joins("\nadd_extension_from_source",...n.splice(1,n.length),t)}const l=/^(latest|lowest|highest|nightly|master|pre|pre-installed|\d+\.x|\d+(\.\d+){0,2})$/;function validatePHPVersionInput(e,t){if(!l.test(e)){throw new Error(`Invalid PHP version in ${t}: ${e.slice(0,20)}`)}return e}async function readPHPVersion(){const e=await getInput("php-version",false);if(e){return validatePHPVersionInput(e,"php-version input")}const t=await getInput("php-version-file",false)||".php-version";if(a.default.existsSync(t)){const e=a.default.readFileSync(t,"utf8");const r=e.match(/^(?:php\s)?(\d+\.\d+\.\d+)$/m);return validatePHPVersionInput(r?r[1]:e.trim(),t)}else if(t!==".php-version"){throw new Error(`Could not find '${t}' file.`)}const r=await readEnv("COMPOSER_PROJECT_DIR");const n=c.join(r,"composer.lock");if(a.default.existsSync(n)){const e=JSON.parse(a.default.readFileSync(n,"utf8"));if(e["platform-overrides"]?.["php"]){return validatePHPVersionInput(e["platform-overrides"]["php"],"composer.lock platform-overrides.php")}}const s=c.join(r,"composer.json");if(a.default.existsSync(s)){const e=JSON.parse(a.default.readFileSync(s,"utf8"));if(e["config"]?.["platform"]?.["php"]){return validatePHPVersionInput(e["config"]["platform"]["php"],"composer.json config.platform.php")}}return"latest"}async function setVariable(e,t,r){switch(r){case"win32":return"\n$"+e+" = "+t+"\n";case"linux":case"darwin":default:return"\n"+e+'="$('+t+')"\n'}}},236:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i{o+=u.write(e);if(l){l(e)}};const stdOutListener=e=>{i+=c.write(e);if(d){d(e)}};const f=Object.assign(Object.assign({},r===null||r===void 0?void 0:r.listeners),{stdout:stdOutListener,stderr:stdErrListener});const p=yield exec(e,t,Object.assign(Object.assign({},r),{listeners:f}));i+=c.end();o+=u.end();return{exitCode:p,stdout:i,stderr:o}})}},665:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i-1){const e=n.substring(0,s);r(e);n=n.substring(s+a.EOL.length);s=n.indexOf(a.EOL)}return n}catch(e){this._debug(`error processing line. Failed with error ${e}`);return""}}_getSpawnFileName(){if(h){if(this._isCmdFile()){return process.env["COMSPEC"]||"cmd.exe"}}return this.toolPath}_getSpawnArgs(e){if(h){if(this._isCmdFile()){let t=`/D /S /C "${this._windowsQuoteCmdArg(this.toolPath)}`;for(const r of this.args){t+=" ";t+=e.windowsVerbatimArguments?r:this._windowsQuoteCmdArg(r)}t+='"';return[t]}}return this.args}_endsWith(e,t){return e.endsWith(t)}_isCmdFile(){const e=this.toolPath.toUpperCase();return this._endsWith(e,".CMD")||this._endsWith(e,".BAT")}_windowsQuoteCmdArg(e){if(!this._isCmdFile()){return this._uvQuoteCmdArg(e)}if(!e){return'""'}const t=[" ","\t","&","(",")","[","]","{","}","^","=",";","!","'","+",",","`","~","|","<",">",'"'];let r=false;for(const n of e){if(t.some(e=>e===n)){r=true;break}}if(!r){return e}let n='"';let s=true;for(let t=e.length;t>0;t--){n+=e[t-1];if(s&&e[t-1]==="\\"){n+="\\"}else if(e[t-1]==='"'){s=true;n+='"'}else{s=false}}n+='"';return n.split("").reverse().join("")}_uvQuoteCmdArg(e){if(!e){return'""'}if(!e.includes(" ")&&!e.includes("\t")&&!e.includes('"')){return e}if(!e.includes('"')&&!e.includes("\\")){return`"${e}"`}let t='"';let r=true;for(let n=e.length;n>0;n--){t+=e[n-1];if(r&&e[n-1]==="\\"){t+="\\"}else if(e[n-1]==='"'){r=true;t+="\\"}else{r=false}}t+='"';return t.split("").reverse().join("")}_cloneExecOptions(e){e=e||{};const t={cwd:e.cwd||process.cwd(),env:e.env||process.env,silent:e.silent||false,windowsVerbatimArguments:e.windowsVerbatimArguments||false,failOnStdErr:e.failOnStdErr||false,ignoreReturnCode:e.ignoreReturnCode||false,delay:e.delay||1e4};t.outStream=e.outStream||process.stdout;t.errStream=e.errStream||process.stderr;return t}_getSpawnOptions(e,t){e=e||{};const r={};r.cwd=e.cwd;r.env=e.env;r["windowsVerbatimArguments"]=e.windowsVerbatimArguments||this._isCmdFile();if(e.windowsVerbatimArguments){r.argv0=`"${t}"`}return r}exec(){return o(this,void 0,void 0,function*(){if(!f.isRooted(this.toolPath)&&(this.toolPath.includes("/")||h&&this.toolPath.includes("\\"))){this.toolPath=d.resolve(process.cwd(),this.options.cwd||process.cwd(),this.toolPath)}this.toolPath=yield l.which(this.toolPath,true);return new Promise((e,t)=>o(this,void 0,void 0,function*(){this._debug(`exec tool: ${this.toolPath}`);this._debug("arguments:");for(const e of this.args){this._debug(` ${e}`)}const r=this._cloneExecOptions(this.options);if(!r.silent&&r.outStream){r.outStream.write(this._getCommandString(r)+a.EOL)}const n=new ExecState(r,this.toolPath);n.on("debug",e=>{this._debug(e)});if(this.options.cwd&&!(yield f.exists(this.options.cwd))){return t(new Error(`The cwd: ${this.options.cwd} does not exist!`))}const s=this._getSpawnFileName();const i=u.spawn(s,this._getSpawnArgs(r),this._getSpawnOptions(this.options,s));let o="";if(i.stdout){i.stdout.on("data",e=>{if(this.options.listeners&&this.options.listeners.stdout){this.options.listeners.stdout(e)}if(!r.silent&&r.outStream){r.outStream.write(e)}o=this._processLineBuffer(e,o,e=>{if(this.options.listeners&&this.options.listeners.stdline){this.options.listeners.stdline(e)}})})}let c="";if(i.stderr){i.stderr.on("data",e=>{n.processStderr=true;if(this.options.listeners&&this.options.listeners.stderr){this.options.listeners.stderr(e)}if(!r.silent&&r.errStream&&r.outStream){const t=r.failOnStdErr?r.errStream:r.outStream;t.write(e)}c=this._processLineBuffer(e,c,e=>{if(this.options.listeners&&this.options.listeners.errline){this.options.listeners.errline(e)}})})}i.on("error",e=>{n.processError=e.message;n.processExited=true;n.processClosed=true;n.CheckComplete()});i.on("exit",e=>{n.processExitCode=e;n.processExited=true;this._debug(`Exit code ${e} received from tool '${this.toolPath}'`);n.CheckComplete()});i.on("close",e=>{n.processExitCode=e;n.processExited=true;n.processClosed=true;this._debug(`STDIO streams have closed for tool '${this.toolPath}'`);n.CheckComplete()});n.on("done",(r,n)=>{if(o.length>0){this.emit("stdline",o)}if(c.length>0){this.emit("errline",c)}i.removeAllListeners();if(r){t(r)}else{e(n)}});if(this.options.input){if(!i.stdin){throw new Error("child process missing stdin")}i.stdin.end(this.options.input)}}))})}}t.ToolRunner=ToolRunner;function argStringToArray(e){const t=[];let r=false;let n=false;let s="";function append(e){if(n&&e!=='"'){s+="\\"}s+=e;n=false}for(let i=0;i0){t.push(s);s=""}continue}append(o)}if(s.length>0){t.push(s.trim())}return t}class ExecState extends c.EventEmitter{constructor(e,t){super();this.processClosed=false;this.processError="";this.processExitCode=0;this.processExited=false;this.processStderr=false;this.delay=1e4;this.done=false;this.timeout=null;if(!t){throw new Error("toolPath must not be empty")}this.options=e;this.toolPath=t;if(e.delay){this.delay=e.delay}}CheckComplete(){if(this.done){return}if(this.processClosed){this._setResult()}else if(this.processExited){this.timeout=(0,p.setTimeout)(ExecState.HandleTimeout,this.delay,this)}}_debug(e){this.emit("debug",e)}_setResult(){let e;if(this.processExited){if(this.processError){e=new Error(`There was an error when attempting to execute the process '${this.toolPath}'. This may indicate the process failed to start. Error: ${this.processError}`)}else if(this.processExitCode!==0&&!this.options.ignoreReturnCode){e=new Error(`The process '${this.toolPath}' failed with exit code ${this.processExitCode}`)}else if(this.processStderr&&this.options.failOnStdErr){e=new Error(`The process '${this.toolPath}' failed because one or more lines were written to the STDERR stream`)}}if(this.timeout){clearTimeout(this.timeout);this.timeout=null}this.done=true;this.emit("done",e,this.processExitCode)}static HandleTimeout(e){if(e.done){return}if(!e.processClosed&&e.processExited){const t=`The STDIO streams did not close within ${e.delay/1e3} seconds of the exit event from process '${e.toolPath}'. This may indicate a child process inherited the STDIO streams and has not yet exited.`;e._debug(t)}e._setResult()}}},207:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;ie.toUpperCase()===t)){return e}}else{if(isUnixExecutable(n)){return e}}}const s=e;for(const i of r){e=s+i;n=undefined;try{n=yield(0,t.stat)(e)}catch(t){if(t.code!=="ENOENT"){console.log(`Unexpected error attempting to determine if executable file exists '${e}': ${t}`)}}if(n&&n.isFile()){if(t.IS_WINDOWS){try{const r=u.dirname(e);const n=u.basename(e).toUpperCase();for(const s of yield(0,t.readdir)(r)){if(n===s.toUpperCase()){e=u.join(r,s);break}}}catch(t){console.log(`Unexpected error attempting to determine the actual case of the file '${e}': ${t}`)}return e}else{if(isUnixExecutable(n)){return e}}}}return""})}function normalizeSeparators(e){e=e||"";if(t.IS_WINDOWS){e=e.replace(/\//g,"\\");return e.replace(/\\\\+/g,"\\")}return e.replace(/\/\/+/g,"/")}function isUnixExecutable(e){return(e.mode&1)>0||(e.mode&8)>0&&process.getgid!==undefined&&e.gid===process.getgid()||(e.mode&64)>0&&process.getuid!==undefined&&e.uid===process.getuid()}function getCmdPath(){var e;return(e=process.env["COMSPEC"])!==null&&e!==void 0?e:`cmd.exe`}},994:function(e,t,r){"use strict";var n=this&&this.__createBinding||(Object.create?function(e,t,r,n){if(n===undefined)n=r;var s=Object.getOwnPropertyDescriptor(t,r);if(!s||("get"in s?!t.__esModule:s.writable||s.configurable)){s={enumerable:true,get:function(){return t[r]}}}Object.defineProperty(e,n,s)}:function(e,t,r,n){if(n===undefined)n=r;e[n]=t[r]});var s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:true,value:t})}:function(e,t){e["default"]=t});var i=this&&this.__importStar||function(){var ownKeys=function(e){ownKeys=Object.getOwnPropertyNames||function(e){var t=[];for(var r in e)if(Object.prototype.hasOwnProperty.call(e,r))t[t.length]=r;return t};return ownKeys(e)};return function(e){if(e&&e.__esModule)return e;var t={};if(e!=null)for(var r=ownKeys(e),i=0;i|]/.test(e)){throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows')}}try{yield u.rm(e,{force:true,maxRetries:3,recursive:true,retryDelay:300})}catch(e){throw new Error(`File was unable to be removed ${e}`)}})}function mkdirP(e){return o(this,void 0,void 0,function*(){(0,a.ok)(e,"a path argument must be provided");yield u.mkdir(e,{recursive:true})})}function which(e,t){return o(this,void 0,void 0,function*(){if(!e){throw new Error("parameter 'tool' is required")}if(t){const t=yield which(e,false);if(!t){if(u.IS_WINDOWS){throw new Error(`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also verify the file has a valid extension for an executable file.`)}else{throw new Error(`Unable to locate executable file: ${e}. Please verify either the file path exists or the file can be found within a directory specified by the PATH environment variable. Also check the file mode to verify the file is executable.`)}}return t}const r=yield findInPath(e);if(r&&r.length>0){return r[0]}return""})}function findInPath(e){return o(this,void 0,void 0,function*(){if(!e){throw new Error("parameter 'tool' is required")}const t=[];if(u.IS_WINDOWS&&process.env["PATHEXT"]){for(const e of process.env["PATHEXT"].split(c.delimiter)){if(e){t.push(e)}}}if(u.isRooted(e)){const r=yield u.tryGetExecutablePath(e,t);if(r){return[r]}return[]}if(e.includes(c.sep)){return[]}const r=[];if(process.env.PATH){for(const e of process.env.PATH.split(c.delimiter)){if(e){r.push(e)}}}const n=[];for(const s of r){const r=yield u.tryGetExecutablePath(c.join(s,e),t);if(r){n.push(r)}}return n})}function readCopyOptions(e){const t=e.force==null?true:e.force;const r=Boolean(e.recursive);const n=e.copySourceDirectory==null?true:Boolean(e.copySourceDirectory);return{force:t,recursive:r,copySourceDirectory:n}}function cpDirRecursive(e,t,r,n){return o(this,void 0,void 0,function*(){if(r>=255)return;r++;yield mkdirP(t);const s=yield u.readdir(e);for(const i of s){const s=`${e}/${i}`;const o=`${t}/${i}`;const a=yield u.lstat(s);if(a.isDirectory()){yield cpDirRecursive(s,o,r,n)}else{yield copyFile(s,o,n)}}yield u.chmod(t,(yield u.stat(e)).mode)})}function copyFile(e,t,r){return o(this,void 0,void 0,function*(){if((yield u.lstat(e)).isSymbolicLink()){try{yield u.lstat(t);yield u.unlink(t)}catch(e){if(e.code==="EPERM"){yield u.chmod(t,"0666");yield u.unlink(t)}}const r=yield u.readlink(e);yield u.symlink(r,t,u.IS_WINDOWS?"junction":null)}else if(!(yield u.exists(t))||r){yield u.copyFile(e,t)}})}},26:function(e,t){(function(e,r){true?r(t):0})(this,function(e){"use strict";const t=/^[v^~<>=]*?(\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+)(?:\.([x*]|\d+))?(?:-([\da-z\-]+(?:\.[\da-z\-]+)*))?(?:\+[\da-z\-]+(?:\.[\da-z\-]+)*)?)?)?$/i;const validateAndParse=e=>{if(typeof e!=="string"){throw new TypeError("Invalid argument expected string")}const r=e.match(t);if(!r){throw new Error(`Invalid argument not valid semver ('${e}' received)`)}r.shift();return r};const isWildcard=e=>e==="*"||e==="x"||e==="X";const tryParse=e=>{const t=parseInt(e,10);return isNaN(t)?e:t};const forceType=(e,t)=>typeof e!==typeof t?[String(e),String(t)]:[e,t];const compareStrings=(e,t)=>{if(isWildcard(e)||isWildcard(t))return 0;const[r,n]=forceType(tryParse(e),tryParse(t));if(r>n)return 1;if(r{for(let r=0;r{const r=validateAndParse(e);const n=validateAndParse(t);const s=r.pop();const i=n.pop();const o=compareSegments(r,n);if(o!==0)return o;if(s&&i){return compareSegments(s.split("."),i.split("."))}else if(s||i){return s?-1:1}return 0};const compare=(e,t,n)=>{assertValidOperator(n);const s=compareVersions(e,t);return r[n].includes(s)};const r={">":[1],">=":[0,1],"=":[0],"<=":[-1,0],"<":[-1],"!=":[-1,1]};const n=Object.keys(r);const assertValidOperator=e=>{if(typeof e!=="string"){throw new TypeError(`Invalid operator type, expected string but got ${typeof e}`)}if(n.indexOf(e)===-1){throw new Error(`Invalid operator, expected one of ${n.join("|")}`)}};const satisfies=(e,t)=>{t=t.replace(/([><=]+)\s+/g,"$1");if(t.includes("||")){return t.split("||").some(t=>satisfies(e,t))}else if(t.includes(" - ")){const[r,n]=t.split(" - ",2);return satisfies(e,`>=${r} <=${n}`)}else if(t.includes(" ")){return t.trim().replace(/\s{2,}/g," ").split(" ").every(t=>satisfies(e,t))}const r=t.match(/^([<>=~^]+)/);const n=r?r[1]:"=";if(n!=="^"&&n!=="~")return compare(e,t,n);const[s,i,o,,a]=validateAndParse(e);const[c,u,d,,l]=validateAndParse(t);const f=[s,i,o];const p=[c,u!==null&&u!==void 0?u:"x",d!==null&&d!==void 0?d:"x"];if(l){if(!a)return false;if(compareSegments(f,p)!==0)return false;if(compareSegments(a.split("."),l.split("."))===-1)return false}const h=p.findIndex(e=>e!=="0")+1;const g=n==="~"?2:h>1?h:1;if(compareSegments(f.slice(0,g),p.slice(0,g))!==0)return false;if(compareSegments(f.slice(g),p.slice(g))===-1)return false;return true};const validate=e=>typeof e==="string"&&/^[v\d]/.test(e)&&t.test(e);const validateStrict=e=>typeof e==="string"&&/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/.test(e);e.compare=compare;e.compareVersions=compareVersions;e.satisfies=satisfies;e.validate=validate;e.validateStrict=validateStrict})},613:e=>{"use strict";e.exports=require("assert")},317:e=>{"use strict";e.exports=require("child_process")},434:e=>{"use strict";e.exports=require("events")},896:e=>{"use strict";e.exports=require("fs")},857:e=>{"use strict";e.exports=require("os")},928:e=>{"use strict";e.exports=require("path")},193:e=>{"use strict";e.exports=require("string_decoder")},557:e=>{"use strict";e.exports=require("timers")}};var t={};function __nccwpck_require__(r){var n=t[r];if(n!==undefined){return n.exports}var s=t[r]={exports:{}};var i=true;try{e[r].call(s.exports,s,s.exports,__nccwpck_require__);i=false}finally{if(i)delete t[r]}return s.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(755);module.exports=r})(); \ No newline at end of file diff --git a/src/install.ts b/src/install.ts index ea4ab9a9..3133a7b6 100644 --- a/src/install.ts +++ b/src/install.ts @@ -17,7 +17,7 @@ export async function getScript(os: string): Promise { const url = 'https://setup-php.com/sponsor'; const filename = os + (await utils.scriptExtension(os)); const script_path = path.join(__dirname, '../src/scripts', filename); - const run_path = script_path.replace(os, 'run'); + const run_path = utils.scriptRunPath(script_path); const extension_csv: string = utils.sanitizeShellInput( await utils.getInput('extensions', false), true diff --git a/src/scripts/darwin.sh b/src/scripts/darwin.sh index f6fe5ea6..32c8b2c0 100644 --- a/src/scripts/darwin.sh +++ b/src/scripts/darwin.sh @@ -174,6 +174,13 @@ get_brewed_php() { fi } +# Install PHP from the architecture-specific php-darwin cache. +add_php_from_cache() { + cache_root="${src:?}/scripts/tools/php-darwin" + PHP_DARWIN_ROOT="$cache_root" bash "$cache_root/scripts/install.sh" \ + "$version" "${debug:?}" "${ts:?}" +} + # Function to setup PHP 5.6 and newer using Homebrew. add_php() { action=$1 @@ -182,6 +189,9 @@ add_php() { php_keg="php@$version$suffix" php_formula="shivammathur/php/$php_keg" if [[ "$existing_version" = "false" || -n "$suffix" || "$action" = "upgrade" ]]; then + if add_php_from_cache; then + return 0 + fi update_dependencies add_brew_tap "$php_tap" fi diff --git a/src/scripts/tools/php-darwin/conf/archive-paths b/src/scripts/tools/php-darwin/conf/archive-paths new file mode 100644 index 00000000..d1e53d49 --- /dev/null +++ b/src/scripts/tools/php-darwin/conf/archive-paths @@ -0,0 +1,5 @@ +# Homebrew prefix roots permitted in an archive and merged during installation. +Cellar +etc +opt +var diff --git a/src/scripts/tools/php-darwin/conf/package.json b/src/scripts/tools/php-darwin/conf/package.json new file mode 100644 index 00000000..05114fab --- /dev/null +++ b/src/scripts/tools/php-darwin/conf/package.json @@ -0,0 +1,12 @@ +{ + "archive_media_type": "application/vnd.shivammathur.php-darwin.cache.layer.v1.tar+zstd", + "artifact_type": "application/vnd.shivammathur.php-darwin.cache.v1", + "compression_level": 19, + "current_version": "8.5", + "image": "ghcr.io/shivammathur/php-darwin", + "max_install_seconds": 60, + "registry_manifest_media_type": "application/vnd.oci.image.manifest.v1+json", + "tap": "shivammathur/php", + "tap_branch": "main", + "tap_repository": "https://github.com/shivammathur/homebrew-php" +} diff --git a/src/scripts/tools/php-darwin/conf/platforms.json b/src/scripts/tools/php-darwin/conf/platforms.json new file mode 100644 index 00000000..e71e427b --- /dev/null +++ b/src/scripts/tools/php-darwin/conf/platforms.json @@ -0,0 +1,16 @@ +{ + "arm64": { + "build_runner": "macos-15", + "brew_prefix": "/opt/homebrew", + "minimum_macos": 15, + "platform_key": "arm64_sequoia", + "test_runners": ["macos-15", "macos-26"] + }, + "x86_64": { + "build_runner": "macos-15-intel", + "brew_prefix": "/usr/local", + "minimum_macos": 15, + "platform_key": "sequoia", + "test_runners": ["macos-15-intel", "macos-26-intel"] + } +} diff --git a/src/scripts/tools/php-darwin/conf/versions b/src/scripts/tools/php-darwin/conf/versions new file mode 100644 index 00000000..74e0c849 --- /dev/null +++ b/src/scripts/tools/php-darwin/conf/versions @@ -0,0 +1,14 @@ +# channel version +stable 5.6 +stable 7.0 +stable 7.1 +stable 7.2 +stable 7.3 +stable 7.4 +stable 8.0 +stable 8.1 +stable 8.2 +stable 8.3 +stable 8.4 +stable 8.5 +nightly 8.6 diff --git a/src/scripts/tools/php-darwin/scripts/existing-paths.sh b/src/scripts/tools/php-darwin/scripts/existing-paths.sh new file mode 100644 index 00000000..c3372178 --- /dev/null +++ b/src/scripts/tools/php-darwin/scripts/existing-paths.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash + +prefix=${1:?} +output=${2:?} +roots_file=${3:?} +path_list="$output.paths.$$" +trap 'rm -f "$path_list"' EXIT + +[ -d "$prefix" ] || { + printf 'Missing Homebrew prefix: %s\n' "$prefix" >&2 + exit 1 +} +[ -f "$roots_file" ] || { + printf 'Missing archive roots: %s\n' "$roots_file" >&2 + exit 1 +} + +: > "$output" || exit 1 +while IFS= read -r managed_dir extra; do + [ -n "$managed_dir" ] || continue + case "$managed_dir" in \#*) continue ;; esac + [ -z "$extra" ] || { + printf 'Invalid archive root: %s %s\n' "$managed_dir" "$extra" >&2 + exit 1 + } + case "$managed_dir" in Cellar|etc|opt|var) ;; *) + printf 'Unsafe archive root: %s\n' "$managed_dir" >&2 + exit 1 + ;; + esac + if [ "$managed_dir" = Cellar ]; then + # One exclusion per existing keg protects its complete subtree and keeps + # the pattern file small even on runner images with hundreds of formulae. + find "$prefix/Cellar" -mindepth 2 -maxdepth 2 -print0 > "$path_list" || exit 1 + else + find "$prefix/$managed_dir" ! -type d -print0 > "$path_list" || exit 1 + fi + while IFS= read -r -d '' existing_path; do + relative_path=${existing_path#"$prefix"/} + case "$relative_path" in *$'\n'*|*$'\r'*) + printf 'Unsupported Homebrew path: %s\n' "$relative_path" >&2 + exit 1 + ;; + esac + tar_pattern=${relative_path//\\/\\\\} + tar_pattern=${tar_pattern//\[/\\[} + tar_pattern=${tar_pattern//\]/\\]} + tar_pattern=${tar_pattern//\*/\\*} + tar_pattern=${tar_pattern//\?/\\?} + printf '%s\n' "$tar_pattern" >> "$output" || exit 1 + done < "$path_list" +done < "$roots_file" diff --git a/src/scripts/tools/php-darwin/scripts/extract.sh b/src/scripts/tools/php-darwin/scripts/extract.sh new file mode 100644 index 00000000..43c6c00e --- /dev/null +++ b/src/scripts/tools/php-darwin/scripts/extract.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +archive=${1:?} +prefix=${2:?} +exclude_file=${3:?} + +[ -f "$archive" ] || { + printf 'Archive not found: %s\n' "$archive" >&2 + exit 1 +} +[ -d "$prefix" ] || { + printf 'Extraction prefix not found: %s\n' "$prefix" >&2 + exit 1 +} +[ -f "$exclude_file" ] || { + printf 'Extraction exclusion list not found: %s\n' "$exclude_file" >&2 + exit 1 +} + +zstd -dc "$archive" | tar -xmpf - --no-same-owner -X "$exclude_file" -C "$prefix" +pipeline_status=("${PIPESTATUS[@]}") +[ "${pipeline_status[0]}" -eq 0 ] && [ "${pipeline_status[1]}" -eq 0 ] diff --git a/src/scripts/tools/php-darwin/scripts/install.sh b/src/scripts/tools/php-darwin/scripts/install.sh new file mode 100644 index 00000000..b634b024 --- /dev/null +++ b/src/scripts/tools/php-darwin/scripts/install.sh @@ -0,0 +1,149 @@ +#!/usr/bin/env bash + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=scripts/lib.sh +. "$script_dir/lib.sh" + +version=${1:-8.5} +build=${2:-release} +ts=${3:-nts} +local_archive=${4:-} +arch=$(php_darwin_normalize_arch "$(uname -m)") +formula=$(php_darwin_formula "$version" "$build" "$ts") +requested_formula=$(php_darwin_requested_formula "$version" "$build" "$ts") +asset=$(php_darwin_asset "$version" "$build" "$ts" "$arch") +expected_prefix=$(php_darwin_expected_prefix "$arch") +tap=$(php_darwin_package_config tap) +archive_roots="$script_dir/../conf/archive-paths" + +[ "$(uname -s)" = Darwin ] || php_darwin_die 'the cache installer only supports macOS' +command -v brew >/dev/null 2>&1 || php_darwin_die 'Homebrew is required' +brew_prefix=$(brew --prefix) +[ "$brew_prefix" = "$expected_prefix" ] || php_darwin_die "architecture $arch requires Homebrew at $expected_prefix, found $brew_prefix" +command -v zstd >/dev/null 2>&1 || php_darwin_die 'zstd is required to extract the cache' +macos_version=$(sw_vers -productVersion) || php_darwin_die 'could not determine the macOS version' +macos_major=${macos_version%%.*} + +while IFS= read -r managed_dir extra; do + [ -n "$managed_dir" ] || continue + case "$managed_dir" in \#*) continue ;; esac + [ -z "$extra" ] || php_darwin_die "invalid archive root: $managed_dir $extra" + case "$managed_dir" in Cellar|etc|opt|var) ;; *) php_darwin_die "unsafe archive root: $managed_dir" ;; esac + [ -d "$brew_prefix/$managed_dir" ] || mkdir -p "$brew_prefix/$managed_dir" || \ + php_darwin_die "could not create Homebrew directory: $brew_prefix/$managed_dir" + [ -w "$brew_prefix/$managed_dir" ] || \ + php_darwin_die "Homebrew directory is not writable: $brew_prefix/$managed_dir" +done < "$archive_roots" + +export HOMEBREW_NO_AUTO_UPDATE=1 +export HOMEBREW_NO_ENV_HINTS=1 +export HOMEBREW_NO_INSTALL_CLEANUP=1 +export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 +export HOMEBREW_NO_INSTALL_FROM_API=1 + +# Use Homebrew to establish the formula source and trust state. In setup-php the +# tap is already present, so this is a local no-op and adds no install request. +brew tap "$tap" || php_darwin_die "could not tap $tap" +brew trust "$tap" || php_darwin_die "could not trust $tap" +brew formula "$tap/$requested_formula" >/dev/null || php_darwin_die "could not resolve $tap/$requested_formula" + +tmp_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-install.XXXXXX") +trap 'rm -rf "$tmp_dir"' EXIT +archive="$tmp_dir/$asset" +external_metadata= + +if [ -n "$local_archive" ]; then + archive=$local_archive + checksum="$local_archive.sha256" + external_metadata="$(dirname "$local_archive")/${asset%.tar.zst}.json" + [ -f "$archive" ] || php_darwin_die "archive not found: $archive" + [ -f "$checksum" ] || php_darwin_die "checksum not found: $checksum" + [ -f "$external_metadata" ] || php_darwin_die "metadata not found: $external_metadata" + expected_hash=$(awk -v name="$asset" '$2 == name { print $1; found=1; exit } END { exit !found }' "$checksum") || \ + php_darwin_die "checksum file does not contain $asset" + [[ "$expected_hash" =~ ^[0-9a-f]{64}$ ]] || php_darwin_die "checksum is invalid for $asset" + actual_hash=$(php_darwin_sha256 "$archive") || php_darwin_die "could not hash $asset" + [ "$actual_hash" = "$expected_hash" ] || php_darwin_die "checksum mismatch for $asset" +else + image=${PHP_DARWIN_IMAGE:-$(php_darwin_package_config image)} + tag="php-$version-$ts-$build" + descriptor="$tmp_dir/descriptor.json" + bash "$script_dir/registry.sh" pull "$image" "$tag" "$asset" "$archive" "$descriptor" || \ + php_darwin_die "could not pull $image:$tag" + if ! jq -e --arg version "$version" --arg build "$build" --arg ts "$ts" \ + --arg artifact_type "$(php_darwin_package_config artifact_type)" \ + --arg manifest_media_type "$(php_darwin_package_config registry_manifest_media_type)" \ + --arg media_type "$(php_darwin_package_config archive_media_type)" \ + --argjson macos_major "$macos_major" \ + '.annotations["com.setup-php.php-darwin.php-version"] == $version and + .annotations["com.setup-php.php-darwin.build"] == $build and + .annotations["com.setup-php.php-darwin.thread-safety"] == $ts and + (.annotations["com.setup-php.php-darwin.minimum-macos"] | tonumber) <= $macos_major and + (.annotations["com.setup-php.php-darwin.homebrew-php-commit"] | + type == "string" and test("^[0-9a-f]{40}$")) and + (.annotations["com.setup-php.php-darwin.source-hash"] | + type == "string" and test("^[0-9a-f]{64}$")) and + (.annotations["org.opencontainers.image.version"] | + type == "string" and startswith($version + ".") and test("^[0-9]+\\.[0-9]+\\.[0-9]+$")) and + .schema_version == 2 and .artifact_type == $artifact_type and + .manifest_media_type == $manifest_media_type and + .layer.mediaType == $media_type' "$descriptor" >/dev/null; then + php_darwin_die 'OCI manifest annotations did not match the request' + fi + tap_path=$(brew --repository "$tap") || php_darwin_die "could not resolve the $tap repository" + current_source_hash=$(HOMEBREW_PHP_PATH="$tap_path" bash "$script_dir/source-hash.sh" "$version") || \ + php_darwin_die "could not compute the installed $tap source hash" + cached_source_hash=$(jq -er '.annotations["com.setup-php.php-darwin.source-hash"]' "$descriptor") || \ + php_darwin_die 'OCI manifest source hash is missing' + [ "$cached_source_hash" = "$current_source_hash" ] || \ + php_darwin_die "cache is stale for the installed $tap formulae" +fi + +if [ -n "$external_metadata" ]; then + if ! jq -e --arg version "$version" --arg build "$build" --arg ts "$ts" \ + --arg arch "$arch" --arg brew_prefix "$brew_prefix" --arg asset "$asset" --arg formula "$formula" \ + --arg expected_commit "${HOMEBREW_PHP_COMMIT:-}" --arg requested_formula "$requested_formula" \ + --argjson macos_major "$macos_major" \ + '.schema == 1 and .php_version == $version and .build == $build and + .thread_safety == $ts and .architecture == $arch and .brew_prefix == $brew_prefix and + .archive == $asset and .formula == $formula and .requested_formula == $requested_formula and + .minimum_macos <= $macos_major and + (.homebrew_php_commit | type == "string" and test("^[0-9a-f]{40}$")) and + ($expected_commit == "" or .homebrew_php_commit == $expected_commit) and + (.formula_sha256 | type == "string" and test("^[0-9a-f]{64}$")) and + (.php_semver | type == "string" and startswith($version + ".") and test("^[0-9]+\\.[0-9]+\\.[0-9]+$")) and + (.packages | type == "array" and length > 0) and any(.packages[]; .name == $formula)' \ + "$external_metadata" >/dev/null; then + php_darwin_die 'archive metadata did not match the runner or request' + fi +fi + +# Let Homebrew remove only the requested PHP formula, then build a literal +# exclusion list for every remaining file and symlink. The archive has no +# directory entries, so tar can stream it straight into the prefix without +# reading, copying, chmodding, or replacing any existing Homebrew path. +if brew list --versions "$formula" >/dev/null 2>&1; then + brew uninstall --force --ignore-dependencies "$formula" >/dev/null || \ + php_darwin_die "could not remove the existing $formula keg" +fi +exclude_file="$tmp_dir/existing-paths.txt" +bash "$script_dir/existing-paths.sh" "$brew_prefix" "$exclude_file" "$archive_roots" || \ + php_darwin_die 'could not record existing Homebrew paths' +bash "$script_dir/extract.sh" "$archive" "$brew_prefix" "$exclude_file" || \ + php_darwin_die "could not extract $asset into Homebrew" + +brew link --overwrite --force "$formula" >/dev/null || php_darwin_die "could not link $formula" +missing=$(brew missing "$formula" 2>&1) +missing_status=$? +[ "$missing_status" -eq 0 ] || [ -n "$missing" ] || php_darwin_die 'Homebrew dependency validation failed without diagnostics' +[ -z "$missing" ] || php_darwin_die "cache has missing Homebrew dependencies: $missing" + +php_bin="$brew_prefix/opt/$formula/bin/php" +[ -x "$php_bin" ] || php_darwin_die "PHP binary missing after cache extraction: $php_bin" +installed_semver=$($php_bin -r 'echo PHP_VERSION;') || php_darwin_die 'cached PHP could not report its version' +[ "${installed_semver%.*}" = "$version" ] || php_darwin_die "cache installed PHP $installed_semver for requested $version" + +if [ -n "${GITHUB_PATH:-}" ]; then + printf '%s\n%s\n' "$brew_prefix/opt/$formula/bin" "$brew_prefix/opt/$formula/sbin" >> "$GITHUB_PATH" +fi +printf 'Installed PHP %s (%s, %s, %s) from %s\n' "$installed_semver" "$build" "$ts" "$arch" "$asset" diff --git a/src/scripts/tools/php-darwin/scripts/lib.sh b/src/scripts/tools/php-darwin/scripts/lib.sh new file mode 100644 index 00000000..a80c8dad --- /dev/null +++ b/src/scripts/tools/php-darwin/scripts/lib.sh @@ -0,0 +1,124 @@ +#!/usr/bin/env bash + +php_darwin_root=${PHP_DARWIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)} + +php_darwin_die() { + printf 'php-darwin: %s\n' "$*" >&2 + exit 1 +} + +php_darwin_validate_version() { + awk '!/^#/ && $2 == version { found=1 } END { exit !found }' version="${1:-}" "$php_darwin_root/conf/versions" || \ + php_darwin_die "unsupported PHP version: ${1:-}" +} + +php_darwin_version_channel() { + awk '!/^#/ && $2 == version { print $1; found=1; exit } END { exit !found }' \ + version="${1:-}" "$php_darwin_root/conf/versions" || \ + php_darwin_die "unsupported PHP version: ${1:-}" +} + +php_darwin_validate_channel() { + local version=${1:-} + local expected=${2:-} + local actual + + case "$expected" in stable|nightly) ;; *) php_darwin_die "unsupported release channel: ${expected:-}" ;; esac + actual=$(php_darwin_version_channel "$version") + [ "$actual" = "$expected" ] || php_darwin_die "PHP $version is $actual, not $expected" +} + +php_darwin_validate_build() { + case "${1:-}" in + release|debug) ;; + *) php_darwin_die "build must be release or debug: ${1:-}" ;; + esac +} + +php_darwin_validate_ts() { + case "${1:-}" in + nts|zts) ;; + *) php_darwin_die "thread safety must be nts or zts: ${1:-}" ;; + esac +} + +php_darwin_normalize_arch() { + case "${1:-$(uname -m)}" in + arm64|aarch64) printf 'arm64\n' ;; + x86_64|amd64) printf 'x86_64\n' ;; + *) php_darwin_die "unsupported architecture: ${1:-}" ;; + esac +} + +php_darwin_expected_prefix() { + jq -er --arg arch "$(php_darwin_normalize_arch "${1:-}")" '.[$arch].brew_prefix' \ + "$php_darwin_root/conf/platforms.json" || php_darwin_die 'Homebrew prefix is not configured' +} + +php_darwin_package_config() { + jq -er --arg key "$1" '.[$key]' "$php_darwin_root/conf/package.json" || \ + php_darwin_die "package configuration is missing: $1" +} + +php_darwin_formula_suffix() { + local build=${1:-release} + local ts=${2:-nts} + local suffix= + + php_darwin_validate_build "$build" + php_darwin_validate_ts "$ts" + [ "$build" = debug ] && suffix=-debug + [ "$ts" = zts ] && suffix="$suffix-zts" + printf '%s\n' "$suffix" +} + +php_darwin_formula() { + local version=$1 + local current_version + local suffix + + php_darwin_validate_version "$version" + suffix=$(php_darwin_formula_suffix "${2:-release}" "${3:-nts}") + current_version=$(php_darwin_package_config current_version) + if [ "$version" = "$current_version" ]; then + printf 'php%s\n' "$suffix" + else + printf 'php@%s%s\n' "$version" "$suffix" + fi +} + +php_darwin_requested_formula() { + local version=$1 + local suffix + + php_darwin_validate_version "$version" + suffix=$(php_darwin_formula_suffix "${2:-release}" "${3:-nts}") + printf 'php@%s%s\n' "$version" "$suffix" +} + +php_darwin_asset() { + local version=$1 + local version_major + local version_minor + local build=${2:-release} + local ts=${3:-nts} + local arch + + IFS=. read -r version_major version_minor _ <<< "$version" + php_darwin_validate_version "$version_major.$version_minor" + php_darwin_validate_build "$build" + php_darwin_validate_ts "$ts" + arch=$(php_darwin_normalize_arch "${4:-}") + printf 'php_%s-%s-%s+darwin_%s.tar.zst\n' "$version" "$ts" "$build" "$arch" +} + +php_darwin_sha256() { + local hash_output + + if command -v sha256sum >/dev/null 2>&1; then + hash_output=$(sha256sum "$1") || return 1 + else + hash_output=$(shasum -a 256 "$1") || return 1 + fi + printf '%s\n' "${hash_output%% *}" +} diff --git a/src/scripts/tools/php-darwin/scripts/registry.sh b/src/scripts/tools/php-darwin/scripts/registry.sh new file mode 100644 index 00000000..8983eaf9 --- /dev/null +++ b/src/scripts/tools/php-darwin/scripts/registry.sh @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=scripts/lib.sh +. "$script_dir/lib.sh" + +manifest_media_type=$(php_darwin_package_config registry_manifest_media_type) +artifact_type=$(php_darwin_package_config artifact_type) +archive_media_type=$(php_darwin_package_config archive_media_type) +configured_layer_count=$(jq 'keys | length' "$script_dir/../conf/platforms.json") || \ + php_darwin_die 'could not read the configured platform count' + +registry_auth() { + registry_image=$1 + [[ "$registry_image" =~ ^[A-Za-z0-9.-]+/[A-Za-z0-9._/-]+$ ]] || \ + php_darwin_die "invalid registry image: $registry_image" + case "$registry_image" in *..*) php_darwin_die "invalid registry image: $registry_image" ;; esac + registry_host=${registry_image%%/*} + registry_repository=${registry_image#*/} + registry_token_url="https://$registry_host/token" + registry_token_args=(--retry 3 --retry-all-errors -fsSLG) + registry_credential=${GHCR_TOKEN:-${GITHUB_TOKEN:-${GH_TOKEN:-}}} + [ -z "$registry_credential" ] || registry_token_args+=(-u "${GITHUB_ACTOR:-token}:$registry_credential") + registry_token_response=$(curl "${registry_token_args[@]}" "$registry_token_url" \ + --data-urlencode "service=$registry_host" \ + --data-urlencode "scope=repository:$registry_repository:pull") || \ + php_darwin_die "could not get a registry token for $registry_image" + registry_token=$(jq -er '.token // .access_token' <<< "$registry_token_response") || \ + php_darwin_die "registry token response was invalid for $registry_image" +} + +registry_manifest() { + manifest_tag=$1 + manifest_output=$2 + manifest_headers=$3 + [[ "$manifest_tag" =~ ^[A-Za-z0-9._-]+$ ]] || php_darwin_die "invalid OCI tag: $manifest_tag" + curl --retry 3 --retry-all-errors -fsSL \ + -H "Authorization: Bearer $registry_token" \ + -H "Accept: $manifest_media_type" \ + -D "$manifest_headers" \ + "https://$registry_host/v2/$registry_repository/manifests/$manifest_tag" \ + -o "$manifest_output" || return 1 + + jq -e --arg archive_media_type "$archive_media_type" --arg artifact_type "$artifact_type" \ + --arg media_type "$manifest_media_type" --argjson layer_count "$configured_layer_count" \ + '.schemaVersion == 2 and .mediaType == $media_type and .artifactType == $artifact_type and + (.layers | type == "array" and length == $layer_count) and + all(.layers[]; + .mediaType == $archive_media_type and + (.digest | type == "string" and test("^sha256:[0-9a-f]{64}$")) and + (.size | type == "number" and . >= 0 and . == floor) and + (.annotations["org.opencontainers.image.title"] | type == "string" and + test("^php_[0-9]+\\.[0-9]+-(nts|zts)-(debug|release)\\+darwin_(arm64|x86_64)\\.tar\\.zst$"))) and + ([.layers[].annotations["org.opencontainers.image.title"]] | unique | length) == $layer_count and + any(.layers[]; .annotations["org.opencontainers.image.title"] | endswith("_arm64.tar.zst")) and + any(.layers[]; .annotations["org.opencontainers.image.title"] | endswith("_x86_64.tar.zst"))' \ + "$manifest_output" >/dev/null || \ + php_darwin_die 'registry returned an invalid php-darwin OCI manifest' + + header_digest=$(awk 'tolower($1) == "docker-content-digest:" {gsub("\\r", "", $2); digest=$2} END {print digest}' "$manifest_headers") || \ + php_darwin_die 'could not read the registry manifest digest header' + manifest_hash=$(php_darwin_sha256 "$manifest_output") || php_darwin_die 'could not hash the OCI manifest' + manifest_digest="sha256:$manifest_hash" + [ -z "$header_digest" ] || [[ "$header_digest" =~ ^sha256:[0-9a-f]{64}$ ]] || \ + php_darwin_die 'registry returned an invalid manifest digest header' + [ -z "$header_digest" ] || [ "$header_digest" = "$manifest_digest" ] || \ + php_darwin_die "registry manifest digest mismatch: expected $header_digest, got $manifest_digest" +} + +registry_inspect() { + inspect_image=$1 + inspect_tag=$2 + inspect_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-registry.XXXXXX") + trap 'rm -rf "$inspect_dir"' EXIT + registry_auth "$inspect_image" + registry_manifest "$inspect_tag" "$inspect_dir/manifest.json" "$inspect_dir/headers" || return 1 + jq -n --arg digest "$manifest_digest" --slurpfile manifest "$inspect_dir/manifest.json" \ + '{digest:$digest,manifest:$manifest[0]}' +} + +registry_inspect_many() { + inspect_image=$1 + shift + inspect_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-registry.XXXXXX") + trap 'rm -rf "$inspect_dir"' EXIT + inspect_jsonl="$inspect_dir/manifests.jsonl" + : > "$inspect_jsonl" + registry_auth "$inspect_image" + inspect_index=0 + for inspect_tag in "$@"; do + [[ "$inspect_tag" =~ ^[A-Za-z0-9._-]+$ ]] || php_darwin_die "invalid OCI tag: $inspect_tag" + inspect_index=$((inspect_index + 1)) + registry_manifest "$inspect_tag" "$inspect_dir/manifest-$inspect_index.json" "$inspect_dir/headers-$inspect_index" || return 1 + jq -cn --arg tag "$inspect_tag" --arg digest "$manifest_digest" \ + --slurpfile manifest "$inspect_dir/manifest-$inspect_index.json" \ + '{key:$tag,value:{digest:$digest,manifest:$manifest[0]}}' >> "$inspect_jsonl" || \ + php_darwin_die "could not record OCI manifest $inspect_tag" + done + jq -s 'from_entries' "$inspect_jsonl" || php_darwin_die 'could not combine OCI manifests' +} + +registry_pull() { + pull_image=$1 + pull_tag=$2 + pull_asset=$3 + pull_output=$4 + pull_descriptor=$5 + pull_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-registry.XXXXXX") + trap 'rm -rf "$pull_dir"' EXIT + registry_auth "$pull_image" + registry_manifest "$pull_tag" "$pull_dir/manifest.json" "$pull_dir/headers" || \ + php_darwin_die "could not fetch $pull_image:$pull_tag" + + jq -c --arg asset "$pull_asset" \ + '[.layers[] | select(.annotations["org.opencontainers.image.title"] == $asset)]' \ + "$pull_dir/manifest.json" > "$pull_dir/layers.json" || php_darwin_die 'could not parse OCI layers' + [ "$(jq 'length' "$pull_dir/layers.json")" -eq 1 ] || \ + php_darwin_die "expected one $pull_asset layer in $pull_tag" + layer_digest=$(jq -er '.[0].digest' "$pull_dir/layers.json") || php_darwin_die 'OCI layer digest is missing' + layer_size=$(jq -er '.[0].size' "$pull_dir/layers.json") || php_darwin_die 'OCI layer size is missing' + [[ "$layer_digest" =~ ^sha256:[0-9a-f]{64}$ ]] || php_darwin_die 'OCI layer digest is invalid' + [[ "$layer_size" =~ ^[0-9]+$ ]] || php_darwin_die 'OCI layer size is invalid' + + curl --retry 3 --retry-all-errors -fsSL \ + -H "Authorization: Bearer $registry_token" \ + "https://$registry_host/v2/$registry_repository/blobs/$layer_digest" \ + -o "$pull_output" || php_darwin_die "could not download $pull_asset" + actual_hash=$(php_darwin_sha256 "$pull_output") || php_darwin_die 'could not hash the OCI archive layer' + actual_digest="sha256:$actual_hash" + [ "$actual_digest" = "$layer_digest" ] || \ + php_darwin_die "registry blob digest mismatch: expected $layer_digest, got $actual_digest" + actual_size=$(wc -c < "$pull_output") + actual_size=${actual_size//[[:space:]]/} + [ "$actual_size" = "$layer_size" ] || \ + php_darwin_die "registry blob size mismatch: expected $layer_size, got $actual_size" + + jq --arg manifest_digest "$manifest_digest" \ + --slurpfile manifest "$pull_dir/manifest.json" \ + --slurpfile layers "$pull_dir/layers.json" \ + '.manifest_digest=$manifest_digest | + .schema_version=$manifest[0].schemaVersion | + .manifest_media_type=$manifest[0].mediaType | + .artifact_type=$manifest[0].artifactType | + .annotations=($manifest[0].annotations // {}) | + .layer=$layers[0][0]' \ + "$script_dir/../templates/oci-descriptor.json" \ + > "$pull_descriptor" || php_darwin_die 'could not write the OCI descriptor' +} + +case "${1:-}" in + inspect) + [ "$#" -eq 3 ] || php_darwin_die 'usage: registry.sh inspect IMAGE TAG' + registry_inspect "$2" "$3" + ;; + inspect-many) + [ "$#" -ge 4 ] || php_darwin_die 'usage: registry.sh inspect-many IMAGE TAG TAG [...]' + registry_inspect_many "$2" "${@:3}" + ;; + pull) + [ "$#" -eq 6 ] || php_darwin_die 'usage: registry.sh pull IMAGE TAG ASSET OUTPUT DESCRIPTOR' + registry_pull "$2" "$3" "$4" "$5" "$6" + ;; + *) php_darwin_die 'usage: registry.sh inspect|inspect-many|pull ...' ;; +esac diff --git a/src/scripts/tools/php-darwin/scripts/source-hash.sh b/src/scripts/tools/php-darwin/scripts/source-hash.sh new file mode 100644 index 00000000..c94be82e --- /dev/null +++ b/src/scripts/tools/php-darwin/scripts/source-hash.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash + +script_dir=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +# shellcheck source=scripts/lib.sh +. "$script_dir/lib.sh" + +version=${1:?} +tap_path=${HOMEBREW_PHP_PATH:-} +php_darwin_validate_version "$version" +repository=$(php_darwin_package_config tap_repository) +branch=$(php_darwin_package_config tap_branch) +tmp_dir=$(mktemp -d "${RUNNER_TEMP:-/tmp}/php-darwin-source.XXXXXX") +trap 'rm -rf "$tmp_dir"' EXIT +hashes="$tmp_dir/formulae.tsv" + +for build in release debug; do + for ts in nts zts; do + formula=$(php_darwin_formula "$version" "$build" "$ts") + formula_file="$tmp_dir/$formula.rb" + if [ -n "$tap_path" ]; then + cp "$tap_path/Formula/$formula.rb" "$formula_file" || php_darwin_die "could not read $formula from the local tap" + else + curl --retry 3 --retry-all-errors -fsSL \ + "${repository/github.com/raw.githubusercontent.com}/$branch/Formula/$formula.rb" \ + -o "$formula_file" || php_darwin_die "could not download $formula" + fi + formula_hash=$(php_darwin_sha256 "$formula_file") || php_darwin_die "could not hash $formula" + printf '%s\t%s\n' "$formula" "$formula_hash" >> "$hashes" || php_darwin_die 'could not record a formula hash' + done +done + +LC_ALL=C sort -u "$hashes" -o "$hashes" || php_darwin_die 'could not sort formula hashes' +php_darwin_sha256 "$hashes" || php_darwin_die 'could not hash formula metadata' diff --git a/src/scripts/tools/php-darwin/templates/oci-descriptor.json b/src/scripts/tools/php-darwin/templates/oci-descriptor.json new file mode 100644 index 00000000..8f2cb50e --- /dev/null +++ b/src/scripts/tools/php-darwin/templates/oci-descriptor.json @@ -0,0 +1,8 @@ +{ + "annotations": {}, + "artifact_type": "", + "layer": {}, + "manifest_digest": "", + "manifest_media_type": "", + "schema_version": 0 +} diff --git a/src/utils.ts b/src/utils.ts index 7323301f..19c619f9 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -407,6 +407,15 @@ export async function scriptExtension(os: string): Promise { } } +/** + * Get the generated run-script path without rewriting parent directories. + * + * @param scriptPath + */ +export function scriptRunPath(scriptPath: string): string { + return path.join(path.dirname(scriptPath), `run${path.extname(scriptPath)}`); +} + /** * Function to get script tool *