def conditionalBackup()

in app/services/NewProjectBackup.scala [328:380]


  def conditionalBackup(projectAndFiles:(ProjectEntry, Seq[FileEntry]), storageDrivers:Map[Int, StorageDriver], storages:Map[Int, StorageEntry]):Future[Either[String, Boolean]] = {
    val p = projectAndFiles._1
    val nonBackupFiles = projectAndFiles._2.filter(_.backupOf.isEmpty)
    if(nonBackupFiles.isEmpty) {
      logger.warn(s"Project ${p.projectTitle} (${p.id}) has no current file")
      Future(Left(s"Project ${p.projectTitle} (${p.id}) has no current file"))
    } else {
      if(nonBackupFiles.length>1) {
        logger.warn(s"Project ${p.projectTitle} (${p.id}) has multiple non-backup files:")
        nonBackupFiles.foreach(f=>logger.warn(s"\t${p.projectTitle} (${p.id}) ${f.filepath} on storage ${f.storageId}"))
      }
      val sourceFile = nonBackupFiles.head

      validateExistingBackups(
        sourceFile,
        projectAndFiles._2.filter(_.backupOf.isDefined).sortBy(_.version)(Ordering.Int.reverse),
        p,
        storageDrivers
      ) match {
        case Failure(err)=>
          Future.failed(err)
        case Success(Left(msg))=>
          logger.info(s"Project ${p.projectTitle} (${p.id}): $msg")
          Future(Right(false))
        case Success(Right(maybeMostRecentBackup))=>
          logger.debug(s"I will back up project ${p.projectTitle} (${p.id})")
          val maybeDestStorage = for {
            sourceStorage <- storages.get(sourceFile.storageId)
            destStorageId <- sourceStorage.backsUpTo
            destStorage <- storages.get(destStorageId)
          } yield destStorage

          maybeDestStorage match {
            case None=>
              Future(
                Left(s"Cannot back up ${p.projectTitle} (${p.id}) because either the source file id ${sourceFile.storageId} is not valid or there is no backup storage configured for it")
              )
            case Some(destStorage)=>
              if(sourceFile.storageId==destStorage.id.get) {
                Future.failed(new RuntimeException(s"Cannot back up ${p.projectTitle} (${p.id}) because storage ${sourceFile.storageId} is configured to back up to itself. This is not supported and can lead to data loss, please fix."))
              } else {
                performBackup(sourceFile, maybeMostRecentBackup, destStorage)
                  .map(_=>Right(true))
                  .recover({
                    case err: Throwable =>
                      Left(s"Cannot back up ${p.projectTitle} (${p.id}) because ${err.getMessage} occurred while copying ${sourceFile.filepath} v${sourceFile.version} from storage ${sourceFile.storageId}")
                  })
              }
          }

      }
    }
  }