diff --git a/addons.xml b/addons.xml
index 9197f386e..8d90c38f7 100644
--- a/addons.xml
+++ b/addons.xml
@@ -39,6 +39,7 @@
+
diff --git a/build.gradle b/build.gradle
index 3fc65c0e6..ac7629e5c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -851,6 +851,179 @@ task getComponent {
getComponentTop(curLocationType)
}
}
+task createComponent {
+ description "Create a new component. Set new component name with -Pcomponent=new_component_name (based on the moqui start component here: https://github.com/moqui/start)"
+ doLast {
+ String curLocationType = file('.git').exists() ? 'git' : 'current'
+ if (project.hasProperty('locationType')) curLocationType = locationType
+
+ if (project.hasProperty('component')) {
+ checkRuntimeDirAndDefaults(curLocationType)
+ Set compsChecked = new TreeSet()
+
+ def startComponentName = 'start'
+
+ File componentDir = getComponent(startComponentName, curLocationType, parseAddons(), parseMyaddons(), compsChecked)
+ if (componentDir?.exists()) {
+ logger.lifecycle("Got component start, dependent components checked: ${compsChecked}")
+
+ def newComponent = file("runtime/component/${component}")
+ def renameSuccessful = componentDir.renameTo(newComponent)
+ if (!renameSuccessful) {
+ logger.error("Failed to rename component start to ${component}. Try removing the existing component directory first or giving this program write permissions.")
+ } else {
+ logger.lifecycle("Renamed component start to ${component}")
+ }
+
+ print "Updated file: "
+ newComponent.eachFileRecurse(groovy.io.FileType.FILES) { file ->
+ try {
+ // If file name is startComponentName.* rename to component.*
+ if (file.name.startsWith(startComponentName)) {
+ String newFileName = (file.name - startComponentName)
+ newFileName = component + newFileName
+ File newFile = new File(file.parent, newFileName)
+ file.renameTo(newFile)
+ file = newFile
+ print "${file.path - newComponent.path - '/'}, "
+ }
+
+ String content = file.text
+ if (content.contains(startComponentName)) {
+ content = content.replaceAll(startComponentName, component)
+ file.text = content
+ print "${file.path - newComponent.path - '/'}, "
+ }
+ } catch (IOException e) {
+ println "Error processing file ${file.path}: ${e.message}"
+ }
+ }
+ print "\n\n"
+ println "Select rest api (r), screens (s), or both (B):"
+ def componentInput = System.in.newReader().readLine()
+ logger.warn("componentInput: ${componentInput}")
+ logger.warn("componentInput: ${componentInput == ''}")
+
+ if (componentInput == 'r') {
+ new File(newComponent, 'screen').deleteDir()
+ new File(newComponent, 'template').deleteDir()
+ new File(newComponent, 'data/AppSeedData.xml').delete()
+ println "Selected rest api so, deleted screen, template, and AppSeedData.xml\n"
+ } else if (componentInput == 's') {
+ new File(newComponent, "services/${component}.rest.xml").delete()
+ new File(newComponent, 'data/ApiSeedData.xml').delete()
+ println "Selected screens so, deleted rest api and ApiSeedData.xml\n"
+ } else if (componentInput == 'b' || componentInput == 'B' || componentInput == '') {
+ println "Selected both rest api and screens\n"
+ } else {
+ println "Invalid input. Try again"
+ newComponent.deleteDir()
+ return
+ }
+
+ println "Are you going to code or test in groovy or java [y/N]"
+ def codeInput = System.in.newReader().readLine()
+
+ if (codeInput == 'y' || codeInput == 'Y') {
+ println "Keeping src folder\n"
+ } else if (codeInput == 'n' || codeInput == 'N' || codeInput == '') {
+ new File(newComponent, 'src').deleteDir()
+ new File(newComponent, 'build.grade').delete()
+ println "Selected no so, deleted src and build.grade\n"
+ } else {
+ println "Invalid input. Try again"
+ newComponent.deleteDir()
+ return
+ }
+
+ println "Setup a git repository [Y/n]"
+ def gitInput = System.in.newReader().readLine()
+ if (gitInput == 'y' || gitInput == 'Y' || gitInput == '') {
+ new File(newComponent, '.git').deleteDir()
+ // Setup git repository
+
+ def grgit = Grgit.init(dir: newComponent.path)
+ grgit.add(patterns: ['.'])
+// grgit.commit(message: 'Initial commit', sign: false)
+ println "Selected yes, so git is initialized\n"
+// println "To push to remote repository, type the git remote url or enter to skip"
+// def remoteUrl = System.in.newReader().readLine()
+// if (remoteUrl != '') {
+// grgit.remote.add(name: 'origin', url: remoteUrl)
+// def branch = grgit.branch.current().name
+// grgit.push(remote: 'origin', refsOrSpecs: [':refs/branch/'+branch])
+// }
+ } else if (gitInput == 'n' || gitInput == 'N') {
+ new File(newComponent, '.git').deleteDir()
+ println "Selected no, so git is not initialized\n"
+ println "Run the following to initialize git repository:\ncd runtime/component/${component} && git init && git add . && git commit -m 'Initial commit' && cd ../../.."
+ } else {
+ println "Invalid input. Try again"
+ newComponent.deleteDir()
+ return
+ }
+
+ println "Add to myaddons.xml [Y/n]"
+ def myaddonsInput = System.in.newReader().readLine()
+ if (myaddonsInput == 'y' || myaddonsInput == 'Y' || myaddonsInput == '') {
+ def myaddonsFile = file('myaddons.xml')
+ if (myaddonsFile.exists()){
+ // Iterate through myaddons file and delete the lines that are
+ def iterator = myaddonsFile.readLines().iterator()
+
+ while (iterator.hasNext()) {
+ def line = iterator.next()
+ if (line.contains("")) {
+ iterator.remove()
+ }
+ }
+ } else {
+ println "myaddons.xml not found. Creating one\nEnter repository github (g), github-ssh (GS), bitbucket (b), or bitbucket-ssh (bs)"
+ def repositoryInput = System.in.newReader().readLine()
+ myaddonsFile.append("")
+ }
+
+ println "Enter the component git repository group"
+ def groupInput = System.in.newReader().readLine()
+
+ println "Enter the component git repository name"
+ def nameInput = System.in.newReader().readLine()
+
+ // get git branch
+ def grgit = Grgit.open(dir: newComponent.path)
+ def branch = grgit.branch.current().name
+
+ myaddonsFile.append("\n ")
+ myaddonsFile.append("\n")
+
+ } else if (myaddonsInput == 'n' || myaddonsInput == 'N') {
+ println "Selected no, so component not added to myaddons.xml\n"
+ } else {
+ println "Invalid input. Try again"
+ newComponent.deleteDir()
+ return
+ }
+
+ }
+ } else {
+ throw new InvalidUserDataException("No component property specified")
+ }
+
+ }
+}
task getCurrent {
description "Get the current archive for a component, also check each component it depends on and if not present get its current archive; requires component property"
doLast { getComponentTop('current') }