MiniDigger/Hangar

View on GitHub
orePlayCommon/app/ore/models/project/io/ProjectFiles.scala

Summary

Maintainability
A
0 mins
Test Coverage
package ore.models.project.io

import scala.language.higherKinds

import java.io.IOException
import java.nio.file.Files._
import java.nio.file.Path
import javax.inject.Inject

import scala.collection.JavaConverters._

import ore.models.project.Project
import ore.OreEnv
import ore.util.OreMDC

import cats.effect.{IO, Resource, Sync}
import cats.syntax.all._
import com.typesafe.scalalogging

/**
  * Handles file management of Projects.
  */
class ProjectFiles @Inject()(val env: OreEnv) {

  private val Logger    = scalalogging.Logger("ProjectFiles")
  private val MDCLogger = scalalogging.Logger.takingImplicit[OreMDC](Logger.underlying)

  /**
    * Returns the specified project's plugin directory.
    *
    * @param owner  Owner name
    * @param name   Project name
    * @return       Plugin directory
    */
  def getProjectDir(owner: String, name: String): Path = getUserDir(owner).resolve(name)

  /**
    * Returns the specified version's directory
    *
    * @param owner   Owner name
    * @param name    Project name
    * @param version Version
    * @return        Version directory
    */
  def getVersionDir(owner: String, name: String, version: String): Path =
    getProjectDir(owner, name).resolve("versions").resolve(version)

  /**
    * Returns the specified user's plugin directory.
    *
    * @param user User name
    * @return     Plugin directory
    */
  def getUserDir(user: String): Path = this.env.plugins.resolve(user)

  /**
    * Renames this specified project in the file system.
    *
    * @param owner    Owner name
    * @param oldName  Old project name
    * @param newName  New project name
    * @return         New path
    */
  def renameProject[F[_]](owner: String, oldName: String, newName: String)(implicit F: Sync[F]): F[Unit] = F.delay {
    val newProjectDir = getProjectDir(owner, newName)
    move(getProjectDir(owner, oldName), newProjectDir)
    ()
  }

  /**
    * Returns the directory that contains a [[Project]]'s custom icons.
    *
    * @param owner  Project owner
    * @param name   Project name
    * @return       Icons directory path
    */
  def getIconsDir(owner: String, name: String): Path = getProjectDir(owner, name).resolve("icons")

  /**
    * Returns the directory that contains a [[Project]]'s main icon.
    *
    * @param owner  Project owner
    * @param name   Project name
    * @return       Icon directory path
    */
  def getIconDir(owner: String, name: String): Path = getIconsDir(owner, name).resolve("icon")

  /**
    * Returns the path to a custom [[Project]] icon, if any, None otherwise.
    *
    * @param owner  Project owner
    * @param name   Project name
    * @return Project icon
    */
  def getIconPath(owner: String, name: String)(implicit mdc: OreMDC): Option[Path] =
    findFirstFile(getIconDir(owner, name))

  /**
    * Returns the path to a custom [[Project]] icon, if any, None otherwise.
    *
    * @param project Project to get icon for
    * @return Project icon
    */
  def getIconPath(project: Project)(implicit mdc: OreMDC): Option[Path] =
    getIconPath(project.ownerName, project.name)

  /**
    * Returns the directory that contains an icon that has not yet been saved.
    *
    * @param owner  Project owner
    * @param name   Project name
    * @return       Pending icon path
    */
  def getPendingIconDir(owner: String, name: String): Path = getIconsDir(owner, name).resolve("pending")

  /**
    * Returns the directory to a custom [[Project]] icon that has not yet been
    * saved.
    *
    * @param project Project to get icon for
    * @return Pending icon path
    */
  def getPendingIconPath(project: Project)(implicit mdc: OreMDC): Option[Path] =
    getPendingIconPath(project.ownerName, project.name)

  /**
    * Returns the directory to a custom [[Project]] icon that has not yet been
    * saved.
    *
    * @param ownerName Owner of the project to get icon for
    * @param name Name of the project to get icon for
    * @return Pending icon path
    */
  def getPendingIconPath(ownerName: String, name: String)(implicit mdc: OreMDC): Option[Path] =
    findFirstFile(getPendingIconDir(ownerName, name))

  private def findFirstFile(dir: Path)(implicit MDC: OreMDC): Option[Path] = {
    if (exists(dir)) {
      Resource
        .fromAutoCloseable(IO(list(dir)))
        .use { stream =>
          IO.pure(stream.iterator.asScala.filterNot(isDirectory(_)).toStream.headOption)
        }
        .recoverWith {
          case e: IOException => IO(MDCLogger.error("an error occurred while searching a directory", e)).as(None)
        }
        .unsafeRunSync()
    } else
      None
  }

}