From 73d39c110a5e6893cc09424ef3481b701e6b697e Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Sat, 13 Sep 2025 22:21:34 -0500 Subject: [PATCH] update --- src/api.js | 209 +++++++++++++++++++++++------------------------------ 1 file changed, 90 insertions(+), 119 deletions(-) diff --git a/src/api.js b/src/api.js index bc8f5b9..1eb033b 100644 --- a/src/api.js +++ b/src/api.js @@ -26,12 +26,7 @@ const cleanOldItems = async () => { try { const key = oldItems.pop(); console.log(`cleaning|key|${key}`); - await s3.send( - new DeleteObjectCommand({ - Bucket: BUCKET, - Key: key, - }), - ); + await s3.send(new DeleteObjectCommand({ Bucket: BUCKET, Key: key })); } catch (err) { console.error(err); } @@ -54,8 +49,9 @@ const createDownloadLink = async (key) => { const getBucketFiles = async (folderName) => { try { - folderName = folderName.toLowerCase(); + folderName = (folderName || "").toLowerCase(); const folderKey = encodeURIComponent(folderName) + "/"; + const data = await s3.send( new ListObjectsCommand({ Bucket: BUCKET, @@ -63,14 +59,15 @@ const getBucketFiles = async (folderName) => { }), ); - // SAFETY: guard undefined Contents and ensure Date is a Date - const ret = (data.Contents || []) - .filter((item) => item.Key !== folderKey) - .map((item) => { + const contents = Array.isArray(data?.Contents) ? data.Contents : []; + + const ret = contents + .filter((obj) => obj.Key !== folderKey) + .map((obj) => { const d = - item.LastModified instanceof Date - ? item.LastModified - : new Date(item.LastModified); + obj.LastModified instanceof Date + ? obj.LastModified + : new Date(obj.LastModified); return { date: d .toLocaleDateString("en-US", { @@ -82,137 +79,111 @@ const getBucketFiles = async (folderName) => { second: "2-digit", }) .replace(/,/g, ""), - sort: d.getTime(), - name: item.Key.replace(folderKey, ""), - key: item.Key, + sort: d.getTime() || 0, + name: (obj.Key || "").replace(folderKey, ""), + key: obj.Key || "", }; }) - .sort((a, b) => { - return a.sort > b.sort ? -1 : a.sort < b.sort ? 1 : 0; - }); + .sort((a, b) => (a.sort > b.sort ? -1 : a.sort < b.sort ? 1 : 0)); const itemCount = {}; const ext = ".tar.gz"; - const filteredItems = ret - .filter((it) => it.name.endsWith(ext)) - .filter((it) => { - if (folderName === "nightly") { - const parts = it.name.split("_"); - const groupId = `${parts[0]}_${parts[3]}_${parts[4]}`; - itemCount[groupId] = itemCount[groupId] || 0; - if (++itemCount[groupId] <= 3) { - return true; + // pick tars to keep (apply nightly policy) + const tars = ret.filter((it) => it.name.endsWith(ext)); + const keepTarKeys = new Set(); + + for (const t of tars) { + if (folderName === "nightly") { + const parts = t.name.split("_"); + // parts[0]=product, parts[3]=platform, parts[4]=arch + const groupId = `${parts[0]}_${parts[3]}_${parts[4]}`; + itemCount[groupId] = itemCount[groupId] || 0; + + if (++itemCount[groupId] <= 3) { + keepTarKeys.add(t.key); + } else { + // mark tar + sidecars old + if (!oldItems.includes(t.key)) { + oldItems.push(t.key, t.key + ".sha256", t.key + ".sig"); } - // mark old: tar + sidecars - if (!oldItems.find((k) => k === it.key)) { - oldItems.push(it.key, it.key + ".sha256", it.key + ".sig"); - if (parts[3] === "windows") { - const setup_key = - it.key.substring(0, it.key.length - ext.length) + "_setup.exe"; - const setup_item = ret.find((r) => r.key === setup_key); - if (setup_item) { - oldItems.push( - setup_key, - setup_key + ".sha256", - setup_key + ".sig", - ); - } - } - - if (parts[3] === "darwin") { - const dmg_key = - it.key.substring(0, it.key.length - ext.length) + ".dmg"; - const dmg_item = ret.find((r) => r.key === dmg_key); - if (dmg_item) { - oldItems.push(dmg_key, dmg_key + ".sha256", dmg_key + ".sig"); - } + // windows companion (_setup.exe) + sidecars + if (parts[3] === "windows") { + const setupKey = + t.key.substring(0, t.key.length - ext.length) + "_setup.exe"; + const setupItem = ret.find((x) => x.key === setupKey); + if (setupItem && !oldItems.includes(setupKey)) { + oldItems.push(setupKey, setupKey + ".sha256", setupKey + ".sig"); + } + } + + // darwin companion (.dmg) + sidecars + if (parts[3] === "darwin") { + const dmgKey = + t.key.substring(0, t.key.length - ext.length) + ".dmg"; + const dmgItem = ret.find((x) => x.key === dmgKey); + if (dmgItem && !oldItems.includes(dmgKey)) { + oldItems.push(dmgKey, dmgKey + ".sha256", dmgKey + ".sig"); } } - return false; } - return true; - }); + } else { + keepTarKeys.add(t.key); + } + } - const totalCount = filteredItems.length * 3; + // fast lookup + const byKey = Object.fromEntries(ret.map((r) => [r.key, r])); - const setup_items = []; - const dmg_items = []; // NEW: keep a separate DMG list - let setup_offset = 0; - let dmg_offset = 0; // NEW: independent DMG offset + // build final list by pushing (no in-place splicing) + const out = []; + for (const t of tars) { + if (!keepTarKeys.has(t.key)) continue; - for (let i = 0; i < totalCount && i < filteredItems.length; i += 3) { - const base = filteredItems[i]; - if (!base) break; // SAFETY guard - const parts = base.name.split("_"); + const parts = t.name.split("_"); + const platform = parts[3]; - // insert tar sidecars for this row - let arr = ret.filter((r) => r.name === base.name + ".sha256"); - filteredItems.splice(i + 1, 0, ...arr); - arr = ret.filter((r) => r.name === base.name + ".sig"); - filteredItems.splice(i + 2, 0, ...arr); + // 1) tar + sidecars + out.push(t); + const tarSha = byKey[t.key + ".sha256"]; + if (tarSha) out.push(tarSha); + const tarSig = byKey[t.key + ".sig"]; + if (tarSig) out.push(tarSig); - // queue windows companion block - if (parts[3] === "windows") { - const setup_key = - base.key.substring(0, base.key.length - ext.length) + "_setup.exe"; - const setup_item = ret.find((r) => r.key === setup_key); - if (setup_item) { - const setup_item2 = ret.find((r) => r.key === setup_key + ".sha256"); - const setup_item3 = ret.find((r) => r.key === setup_key + ".sig"); - setup_items.push([ - { idx: i + 3 + setup_offset }, - setup_item, - setup_item2, - setup_item3, - ]); - setup_offset += 3; + // 2) windows setup + sidecars + if (platform === "windows") { + const setupKey = + t.key.substring(0, t.key.length - ext.length) + "_setup.exe"; + const setup = byKey[setupKey]; + if (setup) { + out.push(setup); + const setupSha = byKey[setupKey + ".sha256"]; + if (setupSha) out.push(setupSha); + const setupSig = byKey[setupKey + ".sig"]; + if (setupSig) out.push(setupSig); } } - // queue darwin companion block - if (parts[3] === "darwin") { - const dmg_key = - base.key.substring(0, base.key.length - ext.length) + ".dmg"; - const dmg_item = ret.find((r) => r.key === dmg_key); - if (dmg_item) { - const dmg_item2 = ret.find((r) => r.key === dmg_key + ".sha256"); - const dmg_item3 = ret.find((r) => r.key === dmg_key + ".sig"); - dmg_items.push([ - { idx: i + 3 + dmg_offset }, // FIX: use dmg_offset - dmg_item, - dmg_item2, - dmg_item3, - ]); - dmg_offset += 3; // FIX: increment dmg_offset + // 3) darwin dmg + sidecars + if (platform === "darwin") { + const dmgKey = t.key.substring(0, t.key.length - ext.length) + ".dmg"; + const dmg = byKey[dmgKey]; + if (dmg) { + out.push(dmg); + const dmgSha = byKey[dmgKey + ".sha256"]; + if (dmgSha) out.push(dmgSha); + const dmgSig = byKey[dmgKey + ".sig"]; + if (dmgSig) out.push(dmgSig); } } } - // insert queued companion blocks - if (dmg_items.length > 0) { - dmg_items.forEach((items) => { - filteredItems.splice(items[0].idx, 0, items[1]); - if (items[2]) filteredItems.splice(items[0].idx + 1, 0, items[2]); - if (items[3]) filteredItems.splice(items[0].idx + 2, 0, items[3]); - }); - } - - if (setup_items.length > 0) { - setup_items.forEach((items) => { - filteredItems.splice(items[0].idx, 0, items[1]); - if (items[2]) filteredItems.splice(items[0].idx + 1, 0, items[2]); - if (items[3]) filteredItems.splice(items[0].idx + 2, 0, items[3]); - }); - } - - return filteredItems; + return out; } catch (err) { console.error(err); + return []; } - - return []; }; export { cleanOldItems, createDownloadLink, getBucketFiles };