"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("fs/promises"),h=require("path"),ce=require("child_process"),ue=require("stream"),At=require("os"),w=require("crypto"),U=require("fs"),le=require("util"),he=require("stream/promises");class Z extends ue.Writable{#t=[];promise;constructor(){super(),this.promise=new Promise(t=>{this._final=t}).then(()=>{const t=Buffer.concat(this.#t);return this.#t=[],t})}_write(t,e,i){this.#t.push(Buffer.isBuffer(t)?t:Buffer.from(t,e)),i()}}class Ht extends Error{constructor(t,e,i,s){super(`Command failed: ${t.join(" ")} ${i?.toString("utf8")??""} ${s?.toString("utf8")??""}`),this.command=t,this.exitCode=e,this.stdout=i,this.stderr=s}}const B=async(a,{logger:t}={},e={})=>{const i=ce.spawn(a[0],a.slice(1),{...e,stdio:"pipe"});t?.write(`[${i.pid}]$ ${a.join(" ")} `),t&&(i.stdout.pipe(t,{end:!1}),i.stderr.pipe(t,{end:!1}));const s=new Z;i.stdout.pipe(s);const n=new Z;i.stderr.pipe(n),await new Promise(c=>i.on("exit",c)),t?.write(`[${i.pid}] Exit code: ${i.exitCode} `);const r=await s.promise,o=await n.promise;if(i.exitCode!==0)throw new Ht(a,i.exitCode,r,o);return{stdout:r,stderr:o}},Tt=async(a,t,e=!1)=>{const i=h.basename(t);if(i==="."||i===".."||i==="")throw new Error(`Invalid path: ${t}`);return h.join(await X(a,h.dirname(t),e),i)},X=async(a,t,e=!1)=>{const i=new Set,s=h.normalize(t).split(h.sep);for(let n=0;n{await u.rm(e,{recursive:!0,force:!0})}}}async resolve(t,e){return await this.mount(),await X(this.mountPath,t,e)}async resolveParent(t,e){return await this.mount(),await Tt(this.mountPath,t,e)}async remove(){const t=this.#t;t&&(this.#t=null,this.#e=null,await B(["buildah","rm",t],this.options))}async run(t,e=[]){return await B(["buildah","run",...e,"--",this.name,...t],this.options)}async commit({timestamp:t=Date.now()}={}){return(await B(["buildah","commit","--timestamp",`${Math.round(t/1e3)}`,this.name],this.options)).stdout.toString("utf8").trim()}async executeStep(t){if(Array.isArray(t))for(const e of t)await this.executeStep(e);else await t(this)}}const Y=async(a,t,e)=>{const i=await D.from(a,e);try{return await t(i)}finally{await i.remove()}},H=async(a,t,e)=>typeof a=="string"?await Y(a,t,e):await t(a),Ut=async({source:a,command:t,buildahRunOptions:e,...i})=>await H(a,async s=>await s.run(t,e),i),kt=/^[\w-]+$/;class Dt{cachePath;constructor(t){this.cachePath=h.resolve(t)}#t(t,e){if(!kt.test(t)||!kt.test(e))throw new Error(`Unsafe image id ${JSON.stringify(t)} or operation key ${JSON.stringify(e)}.`);return h.join(this.cachePath,t,e)}async getEntry(t,e){const i=this.#t(t,e);try{return(await u.readFile(i,"utf8")).trim()||void 0}catch{}}async setEntry(t,e,i){const s=this.#t(t,e);await u.mkdir(h.dirname(s),{recursive:!0}),await u.writeFile(s,i,"utf8")}}let W;const de=()=>{if(!W){const a=h.join(At.homedir(),".buildahcker","cache","containers");W=new Dt(a)}return W},pe=async(a,t,e)=>{const i=await B(["buildah","inspect",...t?["--type",t]:[],"--",a],e);return JSON.parse(i.stdout.toString("utf8"))},Q=async(a,t)=>(await B(["buildah","inspect","--format","{{.FromImageID}}","--type","image","--",a],t)).stdout.toString("utf8").trim();class b{constructor(t,e){this.options=e,this.#t=t}#t;static async from(t,e){const i=t==="scratch"?t:await Q(t,e);if(!i)throw new Error(`Could not get information about image ${t}`);return new b(i,e)}clone(){return new b(this.#t,this.options)}get imageId(){return this.#t}async#e(t,e){return await Y(e??this.#t,async i=>{await i.executeStep(t);const s=await i.commit(this.options?.commitOptions);return e&&(this.#t=s),s},this.options)}async executeStep(t){const e=this.options?.containerCache;if(!e){await this.#e(t);return}if(Array.isArray(t)){for(const r of t)await this.executeStep(r);return}const i=this.#t;let s;const n=await t.getCacheKey?.();if(n&&(s=await e.getEntry(i,n),s))try{s=await Q(s,this.options)}catch{s=void 0}s||(s=await this.#e(t,i),n&&await e.setEntry(i,n,s)),this.#t=s}}const tt=a=>{const t=h.normalize(a).split(h.sep);if(t[t.length-1]===""&&t.pop(),(t[0]==="."||t[0]==="")&&t.shift(),t.length===0||t[0]==="..")throw new Error(`Unsafe path: ${a}`);return t.join(h.sep)},Lt=([a,t])=>[tt(a),t],fe=(a,t)=>at?1:0,we=([a],[t])=>fe(a,t),et=a=>new Map(Object.entries(a).map(Lt).sort(we)),at=async a=>{const t=w.createHash("sha256");for(const[e,i]of a){const s=await i.getHash();t.update(`${e.length},${s.length},`),t.update(e),t.update(s)}return t.digest()},me=a=>(a&u.constants.S_IFMT)===u.constants.S_IFLNK;class it{async getHash(){const t=w.createHash("sha256"),e=await this.getAttributes();t.update(`${e.mode.toString(8)},${e.uid},${e.gid}`);const i=await this.getContentHash();return t.update(i),t.digest()}async writeTo(t){try{(await u.lstat(t)).isDirectory()||await u.rm(t)}catch(i){if(i.code!=="ENOENT")throw i}await this.writeContentTo(t);const e=await this.getAttributes();await u.lchown(t,e.uid,e.gid),me(e.mode)||await u.chmod(t,e.mode)}}class Ot extends it{#t;async getUnderlyingFile(){return this.#t||(this.#t=await this._getFile()),this.#t}async getAttributes(){return await(await this.getUnderlyingFile()).getAttributes()}async getContentHash(){return await(await this.getUnderlyingFile()).getContentHash()}async writeContentTo(t){return await(await this.getUnderlyingFile()).writeContentTo(t)}}class Pt extends it{_modeAllow=65535;_modeMandatory=0;attributes;constructor(t){super(),this.attributes={uid:0,gid:0,mode:420,...t}}async getAttributes(){return{...this.attributes,mode:this.attributes.mode&this._modeAllow|this._modeMandatory}}}class z extends Pt{#t;#e;async getContent(){return this.#t||(this.#t=await this._getContent()),this.#t}async getContentHash(){return this.#e||(this.#e=await this._getContentHash()),this.#e}}class st extends z{constructor(t){super(t),this._modeAllow=~u.constants.S_IFMT,this._modeMandatory=u.constants.S_IFREG}async _getContentHash(){const t=w.createHash("sha256");return t.update(await this.getContent()),t.digest()}async writeContentTo(t){await u.writeFile(t,await this.getContent())}}class nt extends z{constructor(t){super(t),this._modeAllow=0,this._modeMandatory=u.constants.S_IFLNK|511}async _getContentHash(){const t=w.createHash("sha256");return t.update(await this.getContent()),t.digest()}async writeContentTo(t){await u.symlink(await this.getContent(),t)}}class rt extends z{constructor(t){super({mode:493,...t}),this._modeAllow=~u.constants.S_IFMT,this._modeMandatory=u.constants.S_IFDIR}async _getContent(){return et(await this._getDirectoryContent())}async _getContentHash(){return await at(await this.getContent())}async writeContentTo(t){try{await u.mkdir(t)}catch(e){if(e.code!=="EEXIST")throw e}for(const[e,i]of await this.getContent())await i.writeTo(h.join(t,e))}}class Kt extends Ot{constructor(t,e){super(),this.sourceFilePath=t,this.options=e}async _getFile(){const t=this.sourceFilePath,e=await u.lstat(t),i={uid:e.uid,gid:e.gid,mode:e.mode,...this.options?.overrideAttributes};if(e.isDirectory())return new xt(t,i,this.options);if(e.isFile())return new x(t,i);if(e.isSymbolicLink())return new Nt(t,i);throw new Error(`Unsupported file type ${e.mode.toString(8)}`)}}class xt extends rt{constructor(t,e,i){super(e),this.sourceFilePath=t,this.options=i,this.sourceFilePath=t}async _getDirectoryContent(){const t=this.sourceFilePath,e={},i=await u.readdir(t);for(const s of i)e[s]=new Kt(h.join(t,s),this.options);return e}}class x extends st{constructor(t,e){super(e),this.sourceFilePath=t,this.sourceFilePath=t}async _getContent(){return await u.readFile(this.sourceFilePath)}}class Nt extends nt{constructor(t,e){super(e),this.sourceFilePath=t,this.sourceFilePath=t}async _getContent(){return await u.readlink(this.sourceFilePath)}}class be extends rt{content;constructor({content:t={},...e}={}){super(e),this.content=t}async _getDirectoryContent(){return this.content}}class N extends st{content;constructor({content:t="",...e}={}){super(e),this.content=t}async _getContent(){const t=this.content;return Buffer.isBuffer(t)?t:Buffer.from(t,"utf8")}}class ye extends nt{content;constructor({content:t,...e}){super(e),this.content=t}async _getContent(){return this.content}}const ot=a=>{const t=et(a),e=async i=>{for(const[s,n]of t)await n.writeTo(await i.resolve(s))};return e.getCacheKey=async()=>`ADD-FILES-${(await at(t)).toString("base64url")}`,e},Mt=a=>{a=a.map(tt).sort();const t=async e=>{const i=await e.mount();for(const s of a){const n=await Tt(i,s);await u.rm(n,{force:!0,recursive:!0})}};return t.getCacheKey=async()=>{const e=w.createHash("sha256");return e.update(JSON.stringify(a)),`RM-FILES-${e.digest("base64url")}`},t},M=(a,t)=>{const e=async i=>{let s=[...a];s=await t?.beforeRun?.(i,s)??s,await i.run(s,[...t?.buildahArgs??[],...t?.buildahArgsNoHash??[]])};return e.getCacheKey=async()=>{const i=w.createHash("sha256");return i.update(JSON.stringify(a)),i.update(JSON.stringify(t?.buildahArgs??[])),i.update(JSON.stringify(t?.extraHashData??[])),`RUN-${i.digest("base64url")}`},e},zt=(a,{apkCache:t}={})=>{const e={};return t&&(e.buildahArgsNoHash=["--volume",`${t}:/etc/apk/cache:rw`],e.extraHashData=["--volume",":/etc/apk/cache:rw"],e.beforeRun=async()=>{await u.mkdir(t,{recursive:!0})}),M(["apk","add",...a],e)};let V;const ge=()=>(V||(V=h.join(At.homedir(),".buildahcker","cache","apk")),V),Ct=()=>({directories:[],files:[]});class Gt{#t=Ct();#e=".";packagesMap=new Map;addLine(t){if(t.length===0){this.#t=Ct(),this.#e=".";return}if(t[1]!=":")throw new Error("Unexpected line syntax!");const e=t[0],i=t.substring(2);switch(e){case"P":{this.#t.packageName=i,this.packagesMap.set(i,this.#t);break}case"F":{this.#e=i,this.#t.directories.push(i);break}case"R":{const s=h.posix.join(this.#e,i);this.#t.files.push(s);break}}}}const jt=async a=>{const t=await X(a,"lib/apk/db/installed"),e=await u.open(t);try{const i=new Gt;for await(const s of e.readLines())i.addLine(s);return i}finally{await e.close()}},_e=async a=>{try{(await u.readdir(a)).length===0&&await u.rmdir(a)}catch(t){if(t.code!=="ENOENT")throw t}},qt=(a,t)=>{a=a.sort();const e=async i=>{const s=await i.mount(),n=await jt(s),r=[],o=[];for(const c of a){const l=n.packagesMap.get(c);if(!l){t?.write(`Package not installed: ${c} `);continue}r.push(...l.files),o.push(...l.directories)}for(const c of r){const l=await i.resolveParent(c);t?.write(`rm ${c} `),await u.rm(l,{force:!0})}o.sort().reverse();for(const c of o){const l=await i.resolveParent(c);await _e(l)}};return e.getCacheKey=async()=>{const i=w.createHash("sha256");return i.update(JSON.stringify(a)),`APK-REMOVE-${i.digest("base64url")}`},e},Ee=(a=[],t)=>[qt(["apk-tools",...a],t),Mt(["var/lib/apk","lib/apk","etc/apk","usr/share/apk","var/cache/apk"])],v=async a=>(a=h.resolve(a),await u.mkdir(h.dirname(a),{recursive:!0}),await u.writeFile(a,""),a),Wt=async(a,t)=>typeof a=="number"?a:await new Promise((e,i)=>U.open(a,t,(s,n)=>s?i(s):e(n))),Vt=async(a,t)=>typeof t=="number"?void 0:new Promise(e=>U.close(a,e)),ke=le.promisify(U.read),Ce=async(a,t,e)=>{const{buffer:i,bytesRead:s}=await ke(a,{buffer:Buffer.alloc(e),position:t});if(s!==e)throw new Error(`Could not read ${s} bytes from file`);return i},A=async({baseImage:a="alpine",apkPackages:t,commitOptions:e,logger:i,apkCache:s,containerCache:n})=>{const r=await b.from(a,{containerCache:n,commitOptions:e,logger:i});return await r.executeStep(zt(t,{apkCache:s})),r.imageId},ct=async({existingSource:a,command:t,buildahRunOptions:e,...i})=>await Ut({source:a??await A(i),command:t,buildahRunOptions:e,logger:i.logger}),Jt=async({outputCoreFile:a,outputBootFile:t,modules:e,prefix:i,config:s,target:n,grubSource:r,containerCache:o,apkCache:c,logger:l})=>{a=await v(a),r||(r=await A({apkPackages:["grub","grub-bios","grub-efi"],containerCache:o,apkCache:c,logger:l})),await H(r,async d=>{const p=await d.tempFolder();try{s&&await u.writeFile(h.join(p.pathInHost,"config.cfg"),s),await d.run(["grub-mkimage","-O",n??"x86_64-efi","-p",i??"/boot/grub","-o","core.img",...s?["-c","config.cfg"]:[],"--",...e??[]],["--workingdir",p.pathInContainer,"-v",`${a}:${p.pathInContainer}/core.img:rw`]),t&&(t=await v(t),await u.cp(await d.resolve(`usr/lib/grub/${n}/boot.img`),t))}finally{await p.remove()}},{logger:l})},ut=({outputCoreFile:a,outputBootFile:t,modules:e,prefix:i,config:s,target:n,...r})=>{const o=async c=>{const l=await c.resolve(a),d=t?await c.resolve(t):void 0;await Jt({outputCoreFile:l,outputBootFile:d,modules:e,prefix:i,config:s,target:n,...r})};return o.getCacheKey=async()=>{const c=w.createHash("sha256");return c.update(JSON.stringify({outputCoreFile:a,outputBootFile:t,modules:e,prefix:i,config:s,target:n})),`GRUB-MKIMAGE-${c.digest("base64url")}`},o};var I=(a=>(a.EfiSystem="C12A7328-F81F-11D2-BA4B-00A0C93EC93B",a.BiosBoot="21686148-6449-6E6F-744E-656564454649",a.LinuxData="0FC63DAF-8483-4772-8E79-3D69D8477DE4",a))(I||{});const Zt=async a=>{const t=[];let s=2048;const n=["-s","/out","unit","s","mklabel","gpt"];let r=0;for(const c of a.partitions){r++;const l=s,d=Math.ceil(c.size/512/2048)*2048;s+=d,t.push({offset:l*512,size:d*512}),n.push("mkpart",c.name,`${l}`,`${s-1}`),n.push("type",`${r}`,c.type)}n.push("print"),s+=2048;const o=await v(a.outputFile);return await u.truncate(o,s*512),await ct({apkPackages:["parted"],existingSource:a.partedSource,command:["parted",...n],buildahRunOptions:["-v",`${o}:/out:rw`],containerCache:a.containerCache,apkCache:a.apkCache,logger:a.logger}),t},lt=async a=>{const t=a.outputFile,e=await Wt(t,"r+");try{for(const i of a.partitions){const s=U.createWriteStream("",{fd:e,start:i.output.offset,autoClose:!1});if("inputFile"in i){const n=i.input?.offset??0,r=i.input?.size??(await u.stat(i.inputFile)).size-n;if(r>i.output.size)throw new Error(`Partition too small for content: ${r} > ${i.output.size}`);const o=U.createReadStream(i.inputFile,{start:n,end:n+r,autoClose:!1});try{await he.pipeline(o,s)}finally{await o.close()}}else{if(i.inputBuffer.length>i.output.size)throw new Error(`Partition too small for content: ${i.inputBuffer.length} > ${i.output.size}`);await new Promise((n,r)=>s.write(i.inputBuffer,o=>o?r(o):n()))}}}finally{await Vt(e,t)}},R=512,$t=9,Rt=3,$e=90,Re=92,It=440,Ie=510,Bt=102,Qt=12,K=R-Qt,J=K-Qt,Be=2048,Ft=(a,t,e)=>a.writeBigUint64LE(e,t),St=(a,t,e)=>a.writeUint16LE(e,t+8),vt=(a,t,e)=>a.writeUint16LE(e,t+10),Xt=async a=>{const t=a.imageFile,e=await Wt(t,"r+");try{const i=await Ce(e,0,R),s=await u.readFile(a.bootFile);let n=await u.readFile(a.coreFile);if(s.length!==R)throw new Error(`The boot file should have a size of ${R} bytes.`);const r=n.length%R;r!==0&&(n=Buffer.concat([n,Buffer.alloc(R-r)])),i.copy(s,Rt,Rt,$e),i.copy(s,It,It,Ie);const o=BigInt(a.partition.offset>>$t);s.writeBigUint64LE(o,Re),s.writeUInt8(144,Bt),s.writeUInt8(144,Bt+1),Ft(n,K,o+1n),St(n,K,(n.length>>$t)-1),vt(n,K,Be+(R>>4)),Ft(n,J,0n),St(n,J,0),vt(n,J,0),await lt({outputFile:e,partitions:[{inputBuffer:s,output:{offset:0,size:R}},{inputBuffer:n,output:a.partition}]})}finally{await Vt(e,t)}},Yt=async({outputFile:a,variables:t,grubSource:e,containerCache:i,apkCache:s,logger:n})=>{a=await v(a),e||(e=await A({apkPackages:["grub","grub-bios","grub-efi"],containerCache:i,apkCache:s,logger:n})),await H(e,async r=>{const o=await r.tempFolder(),c=["--workingdir",o.pathInContainer];try{await r.run(["grub-editenv","grubenv","create"],c),t&&t.length>0&&await r.run(["grub-editenv","grubenv","set",...t],c),await u.cp(h.join(o.pathInHost,"grubenv"),a)}finally{await o.remove()}},{logger:n})},te=({outputFile:a,variables:t,...e})=>{const i=async s=>{const n=await s.resolve(a);await Yt({outputFile:n,variables:t,...e})};return i.getCacheKey=async()=>{const s=w.createHash("sha256");return s.update(JSON.stringify({outputFile:a,variables:t})),`GRUB-MKENV-${s.digest("base64url")}`},i},ee=async({inputFolder:a,squashfsToolsSource:t,outputFile:e,containerCache:i,apkCache:s,logger:n})=>{e=await v(e);const r=h.relative(e,a),o=[];r.startsWith(`..${h.sep}`)||o.push("-e",r),await ct({apkPackages:["squashfs-tools"],existingSource:t,command:["mksquashfs","/in","/out","-noappend","-no-xattrs",...o],buildahRunOptions:["-v",`${a}:/in:ro`,"-v",`${e}:/out:rw`],containerCache:i,apkCache:s,logger:n})},ht=({inputFolder:a,outputFile:t,...e})=>{const i=async s=>{const n=await s.resolve(a),r=await s.resolve(t);await ee({inputFolder:n,outputFile:r,...e})};return i.getCacheKey=async()=>{const s=w.createHash("sha256");return s.update(JSON.stringify({inputFolder:a,outputFile:t})),`MKSQUASHFS-${s.digest("base64url")}`},i},ae=async({inputFolder:a,mtoolsSource:t,outputFileSize:e,outputFile:i,containerCache:s,apkCache:n,logger:r})=>{t||(t=await A({apkPackages:["mtools"],containerCache:s,apkCache:n,logger:r})),i=await v(i),await u.truncate(i,e),await H(t,async o=>{await o.run(["mformat","-i","/out","-F","::"],["-v",`${i}:/out:rw`]);const c=await u.readdir(a);c.length>0&&await o.run(["mcopy","-i","/out","-s","-b","-p",...c.map(l=>`./${l}`),"::/"],["-v",`${a}:/in:ro`,"-v",`${i}:/out:rw`,"--workingdir","/in"])},{logger:r})},ie=({inputFolder:a,outputFile:t,...e})=>{const i=async s=>{const n=await s.resolve(a),r=await s.resolve(t);await ae({inputFolder:n,outputFile:r,...e})};return i.getCacheKey=async()=>{const s=w.createHash("sha256");return s.update(JSON.stringify({inputFolder:a,outputFile:t,outputFileSize:e.outputFileSize})),`MKVFATFS-${s.digest("base64url")}`},i},se=["ed25519"],Fe=async({outputFolder:a,opensshSource:t,types:e=se,prefix:i="ssh_host_",suffix:s="_key",containerCache:n,apkCache:r,logger:o})=>{const c={};await u.mkdir(a,{recursive:!0});let l=!1;const d=await Promise.all(e.map(async p=>{const f=`${i}${p}${s}`,g=`${f}.pub`;let y=!1;const _=h.join(a,g),E=h.join(a,f);c[f]=new x(E,{mode:384}),c[g]=new x(_,{mode:384});try{const[m,k]=await Promise.all([u.stat(_),u.stat(E)]);if(!m.isFile()||!k.isFile())throw new Error(`${f}.pub or ${f} exists in ${a} and is not a regular file.`);y=!0}catch(m){if(m.code!="ENOENT")throw m;l=!0}return{alreadyPresent:y,keyFile:f,type:p}}));return l&&await H(t??await A({apkPackages:["openssh"],containerCache:n,apkCache:r,logger:o}),async p=>{const f=await p.tempFolder();try{for(const{alreadyPresent:g,type:y,keyFile:_}of d)g||await p.run(["ssh-keygen","-t",y,"-f",_,"-N",""],["-v",`${a}:${f.pathInContainer}`,"--workingdir",f.pathInContainer])}finally{await f.remove()}},{logger:o}),c},dt=async(a,t)=>{const e=new Map;try{return await a(async i=>{if(typeof i!="string"){let s=e.get(i.imageId);s||(s=await D.from(i.imageId,t),e.set(i.imageId,s)),i=await s.resolve(i.file)}return i})}finally{for(const i of e.values())await i.remove()}},Se=async(a,t)=>{t=await v(t),await dt(async e=>{await u.cp(await e(a),t)})},ve=33*1024*1024,ne=async({grubDiskDevice:a="hd0",grubEnvPartitionIndex:t,grubEnvPath:e="/grubenv",grubExtraConfig:i="",grubSourceImage:s,grubSourcePath:n="/usr/lib/grub",grubTimeout:r=3,linuxDiskDevice:o="/dev/sda",rootPartitionAIndex:c,rootPartitionBIndex:l,rootPartitionGrubCfg:d="/boot/grub.cfg",squashfsToolsSource:p,apkCache:f,containerCache:g,logger:y})=>{const _=await b.from(s,{containerCache:g,logger:y});return await _.executeStep([ot({[h.join(n,"grub.cfg")]:new N({content:` insmod all_video set envfile=(${a},gpt${t})/${e} load_env --file $envfile buildahcker_stable buildahcker_new if [ ( $buildahcker_new == b ) -o ( ( $buildahcker_new != a ) -a ( $buildahcker_stable == b ) ) ] ; then set default=b set fallback=a else set default=a set fallback=b fi if [ $buildahcker_new != n ] ; then set buildahcker_new=n save_env --file $envfile buildahcker_stable buildahcker_new fi export buildahcker_params set timeout=${r} ${i} menuentry A --id=a { set root=(${a},gpt${c}) set buildahcker_params="buildahcker_current=a buildahcker_grubenv_device=${o}${t} buildahcker_grubenv=${e} buildahcker_other_root=${o}${l} root=${o}${c}" configfile ${d} } menuentry B --id=b { set root=(${a},gpt${l}) set buildahcker_params="buildahcker_current=b buildahcker_grubenv_device=${o}${t} buildahcker_grubenv=${e} buildahcker_other_root=${o}${c} root=${o}${l}" configfile ${d} } `})}),ht({inputFolder:n,outputFile:"/buildahcker.img",squashfsToolsSource:p,apkCache:f,containerCache:g,logger:y})]),{imageId:_.imageId,file:"buildahcker.img"}},Ae=async({grubSourceImage:a,containerCache:t,logger:e})=>{const i=await b.from(a,{containerCache:t,logger:e});return await i.executeStep([M(["grub-editenv","/buildahcker.img","create"]),M(["grub-editenv","/buildahcker.img","set","buildahcker_stable=a","buildahcker_new=n"])]),{imageId:i.imageId,file:"buildahcker.img"}},re=async({efiPartitionSize:a,grubDiskDevice:t="hd0",grubEnvPath:e="/grubenv",grubPartitionIndex:i,grubSourceImage:s,mtoolsSource:n,useEfi:r,containerCache:o,apkCache:c,logger:l})=>{const d=await b.from("scratch",{containerCache:o,logger:l});return await d.executeStep([te({grubSource:s,outputFile:h.join("efi",e),variables:["buildahcker_stable=a","buildahcker_new=n"],containerCache:o,apkCache:c,logger:l})]),r&&await d.executeStep(ut({outputCoreFile:"efi/EFI/boot/bootx64.efi",grubSource:s,target:"x86_64-efi",modules:["part_gpt","squash4"],prefix:`(${t},gpt${i})/`,containerCache:o,apkCache:c,logger:l})),await d.executeStep(ie({inputFolder:"efi",outputFile:"/buildahcker.img",outputFileSize:a,mtoolsSource:n,apkCache:c,containerCache:o,logger:l})),{imageId:d.imageId,file:"buildahcker.img"}},oe=async({grubDiskDevice:a="hd0",grubPartitionIndex:t,grubSourceImage:e,containerCache:i,apkCache:s,logger:n})=>{const r=await b.from("scratch",{containerCache:i,logger:n});return await r.executeStep([ut({outputCoreFile:"buildahcker_grub_core.img",outputBootFile:"buildahcker_grub_boot.img",grubSource:e,target:"i386-pc",modules:["biosdisk","part_gpt","squash4"],prefix:`(${a},gpt${t})/`,containerCache:i,apkCache:s,logger:n})]),{core:{imageId:r.imageId,file:"buildahcker_grub_core.img"},boot:{imageId:r.imageId,file:"buildahcker_grub_boot.img"}}},He=async({biosBootPartitionSize:a,bootType:t="both",efiPartitionSize:e,grubDiskDevice:i,grubEnvPath:s,grubExtraConfig:n,grubSourceImage:r,grubSourcePath:o,grubTimeout:c,linuxDiskDevice:l,mtoolsSource:d,partedSource:p,rootPartition:f,rootPartitionGrubCfg:g,rootPartitionSize:y,squashfsToolsSource:_,apkCache:E,containerCache:m,logger:k})=>{const G=t==="bios"||t==="both",L=t==="efi"||t==="both";r||(r=await A({apkPackages:[...L?["grub-efi"]:[],...G?["grub-bios"]:[]],apkCache:E,containerCache:m,logger:k}));const C={};let F=0;const pt=G?++F:-1,ft=++F,j=++F,wt=++F,mt=++F,T=G?await oe({grubDiskDevice:i,grubPartitionIndex:j,grubSourceImage:r,apkCache:E,containerCache:m,logger:k}):void 0;T&&(C[pt]={type:I.BiosBoot,name:"biosboot",size:a,file:T.core}),e=Math.max(ve,e??0),C[ft]={name:L?"efi":"grubenv",type:L?I.EfiSystem:I.LinuxData,file:await re({efiPartitionSize:e,grubDiskDevice:i,grubEnvPath:s,grubPartitionIndex:j,grubSourceImage:r,mtoolsSource:d,useEfi:L,apkCache:E,containerCache:m,logger:k})},C[j]={name:"grub",type:I.LinuxData,file:await ne({grubDiskDevice:i,grubEnvPartitionIndex:ft,grubExtraConfig:n,grubSourceImage:r,grubSourcePath:o,grubTimeout:c,linuxDiskDevice:l,rootPartitionAIndex:wt,rootPartitionBIndex:mt,rootPartitionGrubCfg:g,squashfsToolsSource:_,apkCache:E,containerCache:m,logger:k})},C[wt]={name:"systemA",type:I.LinuxData,size:y,file:f},C[mt]={name:"systemB",type:I.LinuxData,size:y};const bt=await b.from("scratch",{containerCache:m,logger:k}),yt=async O=>await dt(async P=>{const q=await O.resolve("buildahcker.img"),gt=[];for(let $=1;$<=F;$++){const S=C[$];gt.push({name:S.name,size:S.size??(await u.stat(await P(S.file))).size,type:S.type})}const _t=await Zt({partitions:gt,outputFile:q,partedSource:p,apkCache:E,containerCache:m,logger:k}),Et=[];for(let $=1;$<=F;$++){const S=C[$];S.file&&Et.push({inputFile:await P(S.file),output:_t[$-1]})}await lt({outputFile:q,partitions:Et}),T&&await Xt({imageFile:q,bootFile:await P(T.boot),coreFile:await P(T.core),partition:_t[pt-1]})});return yt.getCacheKey=async()=>{const O=w.createHash("sha256");return O.update(JSON.stringify(C)),`ABPARTITIONSDISK-${O.digest("base64url")}`},await bt.executeStep(yt),{imageId:bt.imageId,file:"buildahcker.img"}},Te=async({kernelCmdline:a,rootPartitionGrubCfg:t="/boot/grub.cfg",sourceRootImage:e,sourceRootInitrdPath:i="/boot/initramfs-lts",sourceRootKernelPath:s="/boot/vmlinuz-lts",squashfsToolsSource:n,updateToolPath:r="/sbin/buildahckerABTool",apkCache:o,containerCache:c,logger:l})=>{const d=await b.from(e,{containerCache:c,logger:l});return await d.executeStep([ot({[t]:new N({content:`linux ${s} $buildahcker_params${a?` ${a}`:""}${i?` initrd ${i}`:""} `}),[r]:new N({content:`#!/bin/sh set -e function readCmdline() { cat /proc/cmdline | sed -nE 's/^.*[[:space:]]'"$1"'=([^[:space:]]*)([[:space:]]|$).*$/\\1/p' } BUILDHACKER_CURRENT="$(readCmdline buildahcker_current)" BUILDHACKER_CURRENT_ROOT="$(readCmdline root)" BUILDHACKER_OTHER_ROOT="$(readCmdline buildahcker_other_root)" BUILDHACKER_GRUBENV="$(readCmdline buildahcker_grubenv)" BUILDHACKER_GRUBENV_DEVICE="$(readCmdline buildahcker_grubenv_device)" if [ -z "$BUILDHACKER_CURRENT" ] || [ -z "$BUILDHACKER_OTHER_ROOT" ] || [ -z "$BUILDHACKER_GRUBENV" ] || [ -z "$BUILDHACKER_GRUBENV_DEVICE" ] ; then echo Not running in expected buildahcker A/B partition environment. exit 1 fi case "$BUILDHACKER_CURRENT" in 'a') BUILDHACKER_OTHER=b ;; 'b') BUILDHACKER_OTHER=a ;; *) echo Invalid buildahcker_current value: $BUILDHACKER_CURRENT exit 1 ;; esac mkdir -p /run/buildahcker-ab-grubenv if ! mountpoint /run/buildahcker-ab-grubenv &> /dev/null ; then mount -o ro -t vfat $BUILDHACKER_GRUBENV_DEVICE /run/buildahcker-ab-grubenv fi function readGrubenv() { grub-editenv "/run/buildahcker-ab-grubenv$BUILDHACKER_GRUBENV" list | sed -nE 's/(^.*[[:space:]]|^)'"$1"'=([^[:space:]]*)([[:space:]]|$).*$/\\2/p' } function updateGrubenv() { mount -o remount,rw /run/buildahcker-ab-grubenv grub-editenv "/run/buildahcker-ab-grubenv$BUILDHACKER_GRUBENV" set "$@" mount -o remount,ro /run/buildahcker-ab-grubenv } BUILDAHCKER_STABLE=$(readGrubenv buildahcker_stable) BUILDAHCKER_NEW=$(readGrubenv buildahcker_new) case "$*" in 'show' | '') echo Current: "$BUILDHACKER_CURRENT" echo Current root: "$BUILDHACKER_CURRENT_ROOT" echo Other: "$BUILDHACKER_OTHER" echo Other root: "$BUILDHACKER_OTHER_ROOT" echo Stable: "$BUILDAHCKER_STABLE" if [ "$BUILDAHCKER_STABLE" != "$BUILDHACKER_CURRENT" ] ; then echo "Warning: current system is not marked as stable!" fi if [ "$BUILDAHCKER_NEW" != "n" ] ; then echo "Warning: next reboot will be on $BUILDAHCKER_NEW" fi ;; 'update') if [ "$BUILDAHCKER_STABLE" != "$BUILDHACKER_CURRENT" ]; then echo Current system is not marked as stable! echo Updates should only be done from a stable system. echo Use mark-stable or reboot the system before updating. exit 1 fi echo "Target partition: $BUILDHACKER_OTHER_ROOT" echo "Update in progress..." dd of="$BUILDHACKER_OTHER_ROOT" echo "Finished writing on $BUILDHACKER_OTHER_ROOT" updateGrubenv buildahcker_new=$BUILDHACKER_OTHER echo Next reboot will be on "$BUILDHACKER_OTHER"! echo To cancel, use cancel-update or run update with a different update. ;; 'cancel-update') if [ "$BUILDAHCKER_NEW" != "n" ]; then updateGrubenv buildahcker_new=n echo Update cancelled, next reboot will be on "$BUILDHACKER_STABLE" else echo There is no update in progress. fi ;; 'mark-stable') if [ "$BUILDAHCKER_STABLE" != "$BUILDHACKER_CURRENT" ]; then updateGrubenv buildahcker_stable=$BUILDHACKER_CURRENT echo "Current system successfully marked as stable." else echo "Current system was already marked as stable." fi ;; 'is-stable') if [ "$BUILDAHCKER_STABLE" == "$BUILDHACKER_CURRENT" ]; then exit 0 else exit 1 fi ;; *) echo Invalid command: "$*" exit 1 ;; esac `,mode:320})}),ht({inputFolder:".",outputFile:"/buildahcker.img",squashfsToolsSource:n,apkCache:o,containerCache:c,logger:l})]),{imageId:d.imageId,file:"buildahcker.img"}};exports.ApkInstalledDatabaseParser=Gt;exports.BaseDirectory=rt;exports.BaseFile=it;exports.BaseFileWithCachedContent=z;exports.BaseFileWithLoadedAttributes=Pt;exports.BaseRegularFile=st;exports.BaseSymbolicLink=nt;exports.CommandFailed=Ht;exports.Container=D;exports.DiskDirectory=xt;exports.DiskFile=x;exports.DiskLocation=Kt;exports.DiskSymLink=Nt;exports.FSContainerCache=Dt;exports.ImageBuilder=b;exports.MemDirectory=be;exports.MemFile=N;exports.MemSymLink=ye;exports.PartitionType=I;exports.ProxyFile=Ot;exports.WritableBuffer=Z;exports.abpartitionsBiosPartition=oe;exports.abpartitionsDisk=He;exports.abpartitionsGrubEnvPartition=Ae;exports.abpartitionsGrubPartition=ne;exports.abpartitionsGrubenvAndEfiPartition=re;exports.abpartitionsRootPartition=Te;exports.addFiles=ot;exports.apkAdd=zt;exports.apkManuallyRemove=qt;exports.apkRemoveApk=Ee;exports.buildahInspect=pe;exports.copyFileInImage=Se;exports.defaultApkCache=ge;exports.defaultContainerCache=de;exports.defaultSSHKeyGenTypes=se;exports.exec=B;exports.getFullImageID=Q;exports.grubBiosSetup=Xt;exports.grubMkenv=Yt;exports.grubMkenvStep=te;exports.grubMkimage=Jt;exports.grubMkimageStep=ut;exports.hashDirectoryContent=at;exports.mksquashfs=ee;exports.mksquashfsStep=ht;exports.mkvfatfs=ae;exports.mkvfatfsStep=ie;exports.normalizeDirectoryEntries=et;exports.normalizeEntry=Lt;exports.normalizeRelativePath=tt;exports.parted=Zt;exports.prepareApkPackages=A;exports.prepareApkPackagesAndRun=ct;exports.readApkInstalledDatabase=jt;exports.rmFiles=Mt;exports.run=M;exports.runInImageOrContainer=Ut;exports.sshKeygen=Fe;exports.temporaryContainer=Y;exports.useFilesInImages=dt;exports.withImageOrContainer=H;exports.writePartitions=lt;