|  | 
|  | 1 | +package ch.epfl.scala | 
|  | 2 | + | 
|  | 3 | +import ch.epfl.scala.githubapi._ | 
|  | 4 | +import sbt._ | 
|  | 5 | +import sbt.internal.util.complete._ | 
|  | 6 | + | 
|  | 7 | +object AnalyzeDependencyGraphDetailed { | 
|  | 8 | + | 
|  | 9 | +  object Model { | 
|  | 10 | +    trait DetailedAnalysisAction { | 
|  | 11 | +      def name: String | 
|  | 12 | +      def help: String | 
|  | 13 | +    } | 
|  | 14 | +    object DetailedAnalysisAction { | 
|  | 15 | +      case object Get extends DetailedAnalysisAction { | 
|  | 16 | +        val name = "get" | 
|  | 17 | +        val help = "search for a pattern in the dependencies (requires githubGenerateSnapshot)" | 
|  | 18 | +      } | 
|  | 19 | +      case object List extends DetailedAnalysisAction { | 
|  | 20 | +        val name = "list" | 
|  | 21 | +        val help = "list all dependencies matching a pattern (requires githubGenerateSnapshot)" | 
|  | 22 | +      } | 
|  | 23 | +      val values: Seq[DetailedAnalysisAction] = Seq(Get, List) | 
|  | 24 | +      def fromString(str: String): Option[DetailedAnalysisAction] = values.find(_.name == str) | 
|  | 25 | +      case class AnalysisParams(action: DetailedAnalysisAction, arg: Option[String]) | 
|  | 26 | +    } | 
|  | 27 | +    case class AnalysisParams(action: DetailedAnalysisAction, arg: Option[String]) | 
|  | 28 | +  } | 
|  | 29 | +  import Model._ | 
|  | 30 | +  import AnalyzeDependencyGraph.getGithubManifest | 
|  | 31 | + | 
|  | 32 | +  val AnalyzeDependenciesDetailed = "githubAnalyzeDependenciesDetailed" | 
|  | 33 | +  val AnalyzeDependenciesUsage: String = | 
|  | 34 | +    s"""$AnalyzeDependenciesDetailed [${DetailedAnalysisAction.values.map(_.name).mkString("|")}] [pattern]""" | 
|  | 35 | +  val AnalyzeDependenciesDetail: String = s"""Analyze the dependencies based on a search pattern: | 
|  | 36 | +  ${DetailedAnalysisAction.values.map(a => s"${a.name}: ${a.help}").mkString("\n  ")} | 
|  | 37 | +  """ | 
|  | 38 | + | 
|  | 39 | +  private def highlight(string: String, pattern: String): String = | 
|  | 40 | +    string.replaceAll(pattern, s"\u001b[32m${pattern}\u001b[0m") | 
|  | 41 | + | 
|  | 42 | +  private def analyzeDependenciesInternal( | 
|  | 43 | +      state: State, | 
|  | 44 | +      action: DetailedAnalysisAction, | 
|  | 45 | +      pattern: String, | 
|  | 46 | +      originalPattern: String | 
|  | 47 | +  ): Unit = { | 
|  | 48 | +    def getDeps(dependencies: Seq[String], pattern: String): Seq[String] = | 
|  | 49 | +      dependencies.filter(_.contains(pattern)).map(highlight(_, originalPattern)) | 
|  | 50 | + | 
|  | 51 | +    def blue(str: String): String = s"\u001b[34m${str}\u001b[0m" | 
|  | 52 | + | 
|  | 53 | +    def resolvedDeps( | 
|  | 54 | +        tabs: String, | 
|  | 55 | +        acc: Seq[String], | 
|  | 56 | +        resolvedByName: Map[String, DependencyNode], | 
|  | 57 | +        pattern: String, | 
|  | 58 | +        originalPattern: String | 
|  | 59 | +    ): Seq[String] = | 
|  | 60 | +      acc ++ resolvedByName.toSeq.flatMap { | 
|  | 61 | +        case (name, resolved) => | 
|  | 62 | +          val matchingDependencies = getDeps(resolved.dependencies, pattern) | 
|  | 63 | +          if (matchingDependencies.isEmpty) { | 
|  | 64 | +            if (name.contains(pattern)) Seq(tabs + highlight(name, originalPattern)) else Nil | 
|  | 65 | +          } else { | 
|  | 66 | +            matchingDependencies.flatMap { matchingDependency => | 
|  | 67 | +              resolvedDeps("  " + tabs, acc :+ (tabs + matchingDependency), resolvedByName, name, originalPattern) | 
|  | 68 | +            } | 
|  | 69 | +          } | 
|  | 70 | +      } | 
|  | 71 | + | 
|  | 72 | +    val matches = getGithubManifest(state) | 
|  | 73 | +      .flatMap { manifests => | 
|  | 74 | +        manifests.map { | 
|  | 75 | +          case (name, manifest) => | 
|  | 76 | +            manifest -> resolvedDeps("", Nil, manifest.resolved, pattern, originalPattern = pattern) | 
|  | 77 | +        } | 
|  | 78 | +      } | 
|  | 79 | +      .toMap | 
|  | 80 | + | 
|  | 81 | +    action match { | 
|  | 82 | +      case DetailedAnalysisAction.Get => | 
|  | 83 | +        matches.foreach { | 
|  | 84 | +          case (manifest, deps) => | 
|  | 85 | +            println(s"📁 ${blue(manifest.name)}") | 
|  | 86 | +            println(deps.map(dep => s"  $dep").mkString("\n")) | 
|  | 87 | +        } | 
|  | 88 | +      case DetailedAnalysisAction.List => | 
|  | 89 | +        println(matches.values.flatten.filter(_.contains(pattern)).toSet.mkString("\n")) | 
|  | 90 | +    } | 
|  | 91 | +  } | 
|  | 92 | + | 
|  | 93 | +  private def extractPattern(state: State): Parser[AnalysisParams] = | 
|  | 94 | +    Parsers.any.*.map { raw => | 
|  | 95 | +      raw.mkString.trim.split(" ").toSeq match { | 
|  | 96 | +        case Seq(action, arg) => AnalysisParams(DetailedAnalysisAction.fromString(action).get, Some(arg)) | 
|  | 97 | +        case Seq(action)      => AnalysisParams(DetailedAnalysisAction.fromString(action).get, None) | 
|  | 98 | +      } | 
|  | 99 | +    }.failOnException | 
|  | 100 | + | 
|  | 101 | +  val commands: Seq[Command] = Seq( | 
|  | 102 | +    Command(AnalyzeDependenciesDetailed, (AnalyzeDependenciesUsage, AnalyzeDependenciesDetail), AnalyzeDependenciesDetail)( | 
|  | 103 | +      extractPattern | 
|  | 104 | +    )(analyzeDependencies) | 
|  | 105 | +  ) | 
|  | 106 | + | 
|  | 107 | +  private def analyzeDependencies(state: State, params: AnalysisParams): State = { | 
|  | 108 | +    params.arg.foreach(pattern => analyzeDependenciesInternal(state, params.action, pattern, pattern)) | 
|  | 109 | +    state | 
|  | 110 | +  } | 
|  | 111 | +} | 
0 commit comments