app/data/PackageList.scala (82 lines of code) (raw):

package data import com.amazonaws.services.s3.AmazonS3 import models.BakeId import models.BakeId.toFilename import models.{Bake, BakeId} import services.Loggable import fun.mike.dmp.{Diff, DiffMatchPatch} import scala.jdk.CollectionConverters._ import scala.collection.{immutable, mutable} import scala.util.control.NonFatal case class PackageListDiff( previousBakeId: BakeId, removedPackages: List[String], newPackages: List[String], diff: List[Diff] ) object PackageList extends Loggable { val s3PathSlug = "packagelists" def s3Path(bakeId: BakeId) = s"$s3PathSlug/${toFilename(bakeId)}" def s3Url(bakeId: BakeId, bucket: String) = s"s3://$bucket/${s3Path(bakeId)}" def removeNonPackageLines(packages: List[String]): List[String] = { packages.filter { p => !(p.contains("Listing") || p.contains("Installed Packages") || p.contains( "Loaded plugins" )) } } def getPackageList( s3Client: AmazonS3, bakeId: BakeId, bucket: Option[String] ): Either[String, List[String]] = { val maybePackageList: Option[Either[String, List[String]]] = bucket.map { b => val packageListKey = s3Path(bakeId) try { val list = s3Client.getObjectAsString(b, packageListKey) Right(removeNonPackageLines(list.split("\n").toList)) } catch { case NonFatal(e) => val message = s"Failed to fetch package list from S3 bucket $bucket, key $packageListKey. Has the bake finished?" log.warn(message, e) Left(message) } } maybePackageList.getOrElse( Left("Amigo data bucket not defined: can't fetch package list") ) } def diffPackageLists( newPackageList: List[String], oldPackageList: List[String], previousBakeId: BakeId ): PackageListDiff = { val removedPackages = oldPackageList.filter(op => !newPackageList.contains(op)) val newPackages = newPackageList.filter(np => !oldPackageList.contains(np)) val dmp = new DiffMatchPatch() val diff = dmp.diff_main(removedPackages.mkString("\n"), newPackages.mkString("\n")) dmp.diffCleanupSemantic(diff) dmp.Diff_EditCost = 6 dmp.diff_cleanupEfficiency(diff) diff.asScala.foreach(d => d.text = d.text.replace("\n", "<br />")) val scalaDiff: List[Diff] = diff.asScala.toList PackageListDiff(previousBakeId, removedPackages, newPackages, scalaDiff) } def getPackageListDiff( s3Client: AmazonS3, newPackageList: List[String], previousBakeId: Option[BakeId], bucket: Option[String] ): Either[String, PackageListDiff] = { previousBakeId.map { pid => val oldPackageList = getPackageList(s3Client, pid, bucket) for { oldList <- oldPackageList } yield diffPackageLists(newPackageList, oldList, pid) } }.getOrElse(Left("No previous bake to diff with")) }