You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// Name: Install app from dmg in Downloads/// Implementation notes:/// - dmg file name can be different from mounted volume name, e.g. UIBrowser302.dmg -> /Volumes/UI Browser 3.0.2.0/// - dmg might contain License agreement that needs to be accepted, e.g. UIBrowser302.dmg/// - dmg might contain other files than just the app, e.g. Extras folder and README.rtf, see UIBrowser302.dmgimport"@johnlindquist/kit"importfs,{statSync,unlinkSync}from"fs";import{join}from"path";import*asluxonfrom"luxon"import{execa}from"execa";import{execSync}from"child_process"letdownloadsDir=home("Downloads")// Feel free to changeletdmgPaths=awaitglobby("*.dmg",{cwd: downloadsDir})letdmgObjs=dmgPaths.map(path=>({fullPath: join(downloadsDir,path),baseName: path.split("/").pop()?.replace(".dmg",""),createdAt: statSync(join(downloadsDir,path)).ctime.getTime(),sizeInMb: statSync(join(downloadsDir,path)).size/1024/1024})).sort((a,b)=>b.createdAt-a.createdAt)if(dmgObjs.length===0){setPlaceholder("No DMG files found in Downloads directory")}else{letselectedDmgPath=awaitarg({placeholder: "Which dmg?",choices: dmgObjs.map(dmg=>({value: dmg.fullPath,name: dmg.baseName,description: `${luxon.DateTime.fromMillis(dmg.createdAt).toFormat('yyyy-MM-dd HH:mm')} • ${dmg.sizeInMb.toFixed(2)} MB`}))})console.log(`Mounting ${selectedDmgPath}`)letvolumeName=awaitattachDmg(selectedDmgPath)letmountPath=`/Volumes/${volumeName}`;console.log(`Mounted to ${mountPath}`)// Note: Globby did not work for me for mounted volumesletapps=fs.readdirSync(mountPath).filter(f=>f.endsWith(".app"))if(apps.length===0){setPlaceholder("No apps found in the mounted volume")// TODO: Find a better way to do early returns/exits}else{letconfirmed=awaitarg({placeholder: `Found ${apps.length} apps: ${apps.join(", ")}, install?`,choices: ["yes","no"]})if(confirmed!=="yes"){notify("Aborted")process.exit(0)}for(letappofapps){console.log(`Copying ${app} to /Applications folder`);awaitexeca(`cp`,['-a',`${mountPath}/${app}`,'/Applications/']);}console.log(`Detaching ${mountPath}`)awaitdetachDmg(mountPath)letconfirmDeletion=awaitarg({placeholder: `Delete ${selectedDmgPath}?`,choices: ["yes","no"]})if(confirmDeletion==="yes"){console.log(`Deleting ${selectedDmgPath}`)awaittrash(selectedDmgPath)}}}// Helpers// ===asyncfunctionattachDmg(dmgPath: string): Promise<string>{// https://superuser.com/questions/221136/bypass-a-licence-agreement-when-mounting-a-dmg-on-the-command-lineletout=execSync(`yes | PAGER=cat hdiutil attach "${dmgPath}"`).toString()letlines=out.split("\n").reverse()// from the end, find line with volume name// /dev/disk6s2 Apple_HFS /Volumes/UI Browser 3.0.2.0letlineWithVolume=lines.find(line=>line.includes("/Volumes/"))if(!lineWithVolume){thrownewError(`Failed to find volume name in output: ${out}`)}letvolumeName=lineWithVolume.split(`/Volumes/`)[1]returnvolumeName}asyncfunctiondetachDmg(mountPoint: string){awaitexeca('hdiutil',['detach',mountPoint])}
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Screenshot-2024-11-23T10.50.46.mp4
Open install-dmg in Script Kit
Beta Was this translation helpful? Give feedback.
All reactions