All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.boothub.BootHub.groovy Maven / Gradle / Ivy
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.boothub
import groovy.transform.Canonical
import groovy.util.logging.Slf4j
import org.beryx.textio.TextIO
import org.boothub.context.HierarchicalConfigurator
import org.boothub.context.ProjectContext
import org.boothub.repo.RepoCache
import org.boothub.repo.RepoKey
import org.boothub.repo.RepoManager
import org.boothub.repo.SkeletonRepo
import org.kohsuke.github.GitHub
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import static org.boothub.context.ExtUtil.*
@Slf4j
abstract class BootHub implements HierarchicalConfigurator {
static final String ZIP_FILE_PREFIX = "boothub-prj-"
static final String ZIP_FILE_SUFFIX = ".zip"
final TextIO textIO
final SkeletonRepo skeletonRepo
final RepoCache repoCache
String outputDirBasePath
String zipFilesBasePath
boolean autoChooseOutputDir
boolean zipOutput
abstract RepoKey getRepoKey()
abstract void configureGhApi(ProjectContext ctx, TextIO textIO)
@Canonical
private static class GenerationResult {
GenerationResultData resultData
boolean done
}
BootHub(TextIO textIO, SkeletonRepo skeletonRepo, RepoCache repoCache) {
this.textIO = textIO
this.skeletonRepo = skeletonRepo
this.repoCache = repoCache
}
BootHub withOutputDirBasePath(String outputDirBasePath) {
this.outputDirBasePath = outputDirBasePath
this
}
BootHub withZipFilesBasePath(String zipFilesBasePath) {
this.zipFilesBasePath = zipFilesBasePath
this
}
BootHub withAutoChooseOutputDir(boolean autoChooseOutputDir) {
this.autoChooseOutputDir = autoChooseOutputDir
this
}
BootHub withZipOutput(Boolean zipOutput) {
this.zipOutput = zipOutput
this
}
GenerationResultData execute() {
ProjectContext ctx = null
try {
def key = repoKey
Initializr initializr
try {
initializr = Initializr.ofRepoKey(key, repoCache)
} catch (Exception e) {
throw new Exception("Cannot initialize skeleton from $key.url: $e.message")
}
def config = initializr.createConfiguration()
log.debug "contextClass: $config.contextClass"
ctx = config.createProjectContext()
setTextIO(ctx, textIO)
setTemplateDir(ctx, initializr.projectTemplateDir)
configureGhApi(ctx, textIO)
configureInheritedTraitsOfConfigurableTrait(ctx)
textIO.textTerminal.println "\nGenerating project. Please wait..."
def result = generateProject(ctx, initializr)
if(skeletonRepo instanceof RepoManager) {
try {
skeletonRepo.incrementUsageCounter(key.id, key.version.toString())
} catch (Exception e) {
log.error("Cannot increment the usage counter.", e)
}
}
result
} catch (Exception e) {
log.error("Errors occurred.", e)
new GenerationResultData(ghProjectId: ctx?.ghProjectId, errorMessage: "Errors occurred: $e.message")
}
}
private GenerationResultData generateProject(ProjectContext ctx, Initializr initializr) {
GitHub gitHub = getGitHubApi(ctx)
while (true) {
def onGitHub = ctx.ghApiUsed && gitHub && gitHub.isCredentialValid()
GenerationResult result = onGitHub ? generateOnGitHub(initializr, ctx) : generateLocally(initializr, ctx)
if(result.done) {
result.resultData.instructions = initializr.getMergedContent(Paths.get('instructions.md'), ctx)
return result.resultData
}
}
}
private GenerationResult generateOnGitHub(Initializr initializr, ProjectContext ctx) {
try {
String workingCopyPath = Util.createTempDirWithDeleteOnExit().toAbsolutePath().toString()
initializr.withOutputDir(workingCopyPath).generateWithContext(ctx)
def repo = GitHubUtil.createRepo(ctx)
GitHubUtil.addContent(ctx, repo, workingCopyPath)
new GenerationResult(done: true, resultData: new GenerationResultData(ghProjectId: ctx.ghProjectId, gitHubRepoLink: "https://github.com/$ctx.ghProjectOwner/$ctx.ghProjectId"))
} catch (Exception e) {
log.warn("Error generating GitHub project", e)
textIO.textTerminal.println("An error occurred: $e" as String)
def option = textIO.newStringInputReader()
.withPromptAdjustments(false)
.withInlinePossibleValues("t", "z", "a")
.withIgnoreCase()
.read("(T)ry again, generate (z)ip file or (a)bort? ")
switch (option) {
case "t": return new GenerationResult(done: false)
case "z": ctx.ghApiUsed = false; return new GenerationResult(done: false)
default: return new GenerationResult(done: true, resultData: new GenerationResultData(ghProjectId: ctx.ghProjectId, errorMessage: "Project generation aborted"))
}
}
}
private GenerationResult generateLocally(Initializr initializr, ProjectContext ctx) {
try {
Path basePath = outputDirBasePath ? Paths.get(outputDirBasePath) : null
String outputDir
if(autoChooseOutputDir) {
def prefix = "boothub-out-"
def outDirPath = basePath ? Files.createTempDirectory(basePath, prefix) : Files.createTempDirectory(prefix)
outputDir = outDirPath.toAbsolutePath().toFile().absolutePath
log.debug("outputPath: $outputDir")
} else {
while (true) {
outputDir = textIO.newStringInputReader().read("Output dir")
if (createDir("$outputDir/$ctx.ghProjectId")) break
}
}
String prjOutputDir = "$outputDir/$ctx.ghProjectId"
initializr.withOutputDir(prjOutputDir).generateWithContext(ctx)
def outputPath = prjOutputDir
if(zipOutput) {
def zipBasePath = basePath
if(zipFilesBasePath) {
zipBasePath = Paths.get(zipFilesBasePath)
}
def zipPath = zipBasePath ? Files.createTempFile(zipBasePath, ZIP_FILE_PREFIX, ZIP_FILE_SUFFIX) : Files.createTempFile(ZIP_FILE_PREFIX, ZIP_FILE_SUFFIX)
zipPath.toFile().delete()
outputPath = zipPath.toAbsolutePath().toFile().absolutePath
def ant = new AntBuilder()
ant.zip(destfile: outputPath, basedir: outputDir, defaultexcludes: 'no')
}
new GenerationResult(done: true, resultData: new GenerationResultData(ghProjectId: ctx.ghProjectId, outputPath: outputPath))
} catch(Exception e) {
log.warn("Error generating project", e)
textIO.textTerminal.println("An error occurred: $e" as String)
new GenerationResult(done: !textIO.newBooleanInputReader().read("Retry?"))
}
}
private boolean createDir(String path) {
File dir = new File(path)
if(dir.isFile()) {
if(!textIO.newBooleanInputReader().read("File $path already exists. Delete?")) return false
if(!dir.delete()) {
textIO.textTerminal.println("Cannot delete file $path" as String)
return false
}
}
if(dir.list()) {
if(!textIO.newBooleanInputReader().read("Directory $path already exists and is not empty. Delete?")) return false
if(!dir.deleteDir()) {
textIO.textTerminal.println("Cannot delete directory $path" as String)
return false
}
}
if(!dir.isDirectory()) dir.mkdirs()
if(!dir.isDirectory()) {
textIO.textTerminal.println("Cannot create the directory $path" as String)
return false
}
return true
}
}