Skip to content

Commit

Permalink
The story so far...
Browse files Browse the repository at this point in the history
  • Loading branch information
thinkmorestupidless committed Jul 7, 2023
1 parent dff2538 commit f2ee46e
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 18 deletions.
11 changes: 11 additions & 0 deletions cmta/src/main/scala/com/lunatech/cmt/admin/Domain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ package com.lunatech.cmt.admin
* See the License for the specific language governing permissions and limitations under the License.
*/

import com.lunatech.cmt.Domain.InstallationSource.GithubProject
import sbt.io.syntax.File

object Domain:
Expand All @@ -37,3 +38,13 @@ object Domain:
final case class LinearizeBaseDirectory(value: File)
final case class MainRepository(value: File)
final case class ConfigurationFile(value: File)

final case class CourseTemplate(value: GithubProject)
object CourseTemplate:
def fromString(str: String): CourseTemplate =
if (str.indexOf("/") > 0) {
val Array(organisation, project) = str.split("/").map(_.trim)
CourseTemplate(GithubProject(organisation, project))
} else {
CourseTemplate(GithubProject("lunatech-labs", str))
}
4 changes: 3 additions & 1 deletion cmta/src/main/scala/com/lunatech/cmt/admin/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@ package com.lunatech.cmt.admin
* See the License for the specific language governing permissions and limitations under the License.
*/

import caseapp.core.app.{CommandsEntryPoint}
import caseapp.core.app.CommandsEntryPoint
import com.lunatech.cmt.admin.command.{
Delinearize,
DuplicateInsertBefore,
Linearize,
New,
RenumberExercises,
Studentify,
Version
Expand All @@ -26,6 +27,7 @@ import com.lunatech.cmt.admin.command.{
object Main extends CommandsEntryPoint:
override def progName = "cmta"
override def commands = Seq(
New.command,
Delinearize.command,
DuplicateInsertBefore.command,
Linearize.command,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,7 @@ object ArgParsers:
given renumberOffsetArgParser: ArgParser[RenumberOffset] =
intGreaterThanZero.xmap[RenumberOffset](_.value, RenumberOffset(_))

given courseTemplateArgParser: ArgParser[CourseTemplate] =
SimpleArgParser.from[CourseTemplate]("Course Template")(str => CourseTemplate.fromString(str).asRight)

end ArgParsers
55 changes: 44 additions & 11 deletions cmta/src/main/scala/com/lunatech/cmt/admin/command/New.scala
Original file line number Diff line number Diff line change
@@ -1,30 +1,63 @@
package com.lunatech.cmt.admin.command

import caseapp.RemainingArgs
import com.lunatech.cmt.CmtError
import com.lunatech.cmt.core.cli.CmtCommand
import com.lunatech.cmt.core.execution.Executable
import caseapp.{AppName, CommandName, ExtraName, HelpMessage, RemainingArgs, ValueDescription}
import com.lunatech.cmt.{CmtError, printResult}
import com.lunatech.cmt.admin.Domain.{ConfigurationFile, CourseTemplate}
import com.lunatech.cmt.client.command.{Executable, Install}
import com.lunatech.cmt.core.validation.Validatable
import com.lunatech.cmt.admin.cli.ArgParsers.{configurationFileArgParser, courseTemplateArgParser}
import com.lunatech.cmt.client.Configuration
import com.lunatech.cmt.client.cli.CmtcCommand
import sbt.io.IO as sbtio
import sbt.io.syntax.*

import java.io.FileFilter

object New:

final case class Options()
@AppName("new")
@CommandName("new")
@HelpMessage(
"Create a new course from an existing course template in a Github repository - by default the `lunatech-labs` organisation is used.")
final case class Options(
@ExtraName("t")
@ValueDescription(
"the template course to use - provide in the format 'organisation/project' or just 'project' if the project is in the lunatech-labs organisation on Github")
template: CourseTemplate,
@ExtraName("c")
@ValueDescription("The (optional) configuration file to use during processing of the command")
@HelpMessage(
"if not specified will default to the config file present in the directory provided by the --main-repository argument")
maybeConfigFile: Option[ConfigurationFile] = None)

given Validatable[New.Options] with
extension (options: New.Options)
def validated(): Either[CmtError, New.Options] =
Right(options)
end given

given Executable[Delinearize.Options] with
extension (options: Delinearize.Options)
def execute(): Either[CmtError, String] = {
???
given Executable[New.Options] with
extension (options: New.Options)
def execute(configuration: Configuration): Either[CmtError, String] = {
// list the contents of the ~/Courses directory, if there's anything already matching the name then get the count so we can append to the name and prevent conflicts
val existingFilesWithSameName = sbtio.listFiles(
configuration.coursesDirectory.value,
new FileFilter {
override def accept(file: File): Boolean =
file.name.startsWith(options.template.value.project)
})
val discriminator = if (existingFilesWithSameName.size > 0) s"-${existingFilesWithSameName.size}" else ""
val targetDirectoryName = s"${options.template.value.project}$discriminator"

// Install the course
Install
.Options(options.template.value, newName = Some(targetDirectoryName), studentifiedAsset = Some(false))
.execute(configuration)
}

val command = new CmtCommand[New.Options] {
val command = new CmtcCommand[New.Options] {
def run(options: New.Options, args: RemainingArgs): Unit =
options.validated().flatMap(_.execute()).printResult()
options.validated().flatMap(_.execute(configuration)).printResult()
}

end New
30 changes: 24 additions & 6 deletions core/src/main/scala/com/lunatech/cmt/client/command/Install.scala
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@ object Install:
"Install a course - from either a local directory, a zip file on the local file system or a Github project")
final case class Options(
@ExtraName("s")
source: InstallationSource)
source: InstallationSource,
@ExtraName("d")
newName: Option[String] = None,
@ExtraName("a")
studentifiedAsset: Option[Boolean] = Some(true))

given Validatable[Install.Options] with
extension (options: Install.Options)
Expand Down Expand Up @@ -93,11 +97,13 @@ object Install:
release: Release,
configuration: Configuration)(implicit client: Client[IO]): Either[CmtError, String] =
for {
studentAssetUrl <- getStudentAssetUrl(githubProject, release)
_ = printMessage(s"downloading studentified course from '$studentAssetUrl' to courses directory")
downloadedZipFile <- downloadStudentAsset(studentAssetUrl, githubProject, release.tag_name, configuration)
assetUrl <- getAssetUrl(githubProject, release)
_ = printMessage(s"downloading studentified course from '$assetUrl' to courses directory")
downloadedZipFile <- downloadStudentAsset(assetUrl, githubProject, release.tag_name, configuration)
_ <- installFromZipFile(downloadedZipFile, configuration, deleteZipAfterInstall = true)
_ <- setCurrentCourse(githubProject, configuration)
_ <-
if (cmd.studentifiedAsset.getOrElse(true)) setCurrentCourse(githubProject, configuration)
else "successfully created new course".toExecuteCommandErrorMessage.asRight
} yield s"${githubProject.project} (${release.tag_name}) successfully installed to ${configuration.coursesDirectory.value}/${githubProject.project}"

private def setCurrentCourse(
Expand All @@ -108,12 +114,24 @@ object Install:
SetCurrentCourse.Options(studentifiedRepo).execute(configuration)
}

private def getAssetUrl(githubProject: GithubProject, release: Release)(implicit
httpClient: Client[IO]): Either[CmtError, String] = {
if (cmd.studentifiedAsset.getOrElse(true)) {
getStudentAssetUrl(githubProject, release)
} else {
release.zipball_url.toRight(
s"latest release of ${githubProject.displayName} does not have a 'main' repo zip - unable to install without one".toExecuteCommandErrorMessage)
}
}

private def getStudentAssetUrl(githubProject: GithubProject, release: Release)(implicit
httpClient: Client[IO]): Either[CmtError, String] = {
val maybeAssetsFuture = httpClient
.expect[List[Asset]](release.assets_url)
.map { assets =>
val requiredName = s"${githubProject.project}-student.zip"
val requiredName =
if (cmd.studentifiedAsset.getOrElse(true)) s"${githubProject.project}-student.zip"
else s"${githubProject.project}-${release.tag_name}.zip"
assets.find(_.name == requiredName).map(_.browserDownloadUrl)
}
.unsafeToFuture()
Expand Down

0 comments on commit f2ee46e

Please sign in to comment.