/******************************************************************************* * Copyright (c) May 16, 2011 Zend Technologies Ltd. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.zend.sdkcli.internal.commands; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.text.MessageFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jgit.api.CloneCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.InvalidRemoteException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.TransportException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.TextProgressMonitor; import org.zend.sdkcli.internal.mapping.CliMappingLoader; import org.zend.sdkcli.internal.options.Option; import org.zend.sdklib.application.ZendProject; import org.zend.sdklib.application.ZendProject.TemplateApplications; import org.zend.sdklib.project.DeploymentScriptTypes; /** * Represents create-project command. In the result of calling it new PHP * project is created in defined location or a current location. * * @author Wojciech Galanciak, 2011 * */ public class CreateProjectCommand extends AbstractCommand { public static final String NAME = "n"; public static final String SCRIPTS = "s"; public static final String DESTINATION = "d"; public static final String TEMPLATE = "t"; /** * @return The project destination */ @Option(opt = DESTINATION, required = false, description = "Project destination", argName = "path") public File getDestination() { final String value = getValue(DESTINATION); return value == null ? resolveDestination(getCurrentDirectory(), getName()) : new File(value); } @Option(opt = SCRIPTS, required = false, description = "Generate deployment scripts, " + "consider using one of these options [all|postActivate|postDeactivate|postStage|postUnstage|preActivate|preDeactivate|preStage|preUnstage]") public String getScripts() { return getValue(SCRIPTS); } /** * @return The project name */ @Option(opt = NAME, required = true, description = "Project name", argName = "name") public String getName() { return getValue(NAME); } /** * @return The project name */ @Option(opt = TEMPLATE, required = false, description = "Template name (zend | zf2 | quickstart | simple). Default is zend application", argName = "name") public TemplateApplications getTemplate() { TemplateApplications result = TemplateApplications.getDefault(); final String value = getValue(TEMPLATE); if (value != null) { try { result = TemplateApplications.valueOf(value.toUpperCase()); } catch (Exception e) { return null; } } return result; } @Override public boolean doExecute() { File destinationFolder = getDestination(); if (doOverwite(destinationFolder)) { ZendProject project = new ZendProject(getDestination(), new CliMappingLoader()); TemplateApplications template = getTemplate(); if (template == null) { getLogger() .error(MessageFormat .format("Cannot create a project. \"{0}\" is not a valid template name", getValue(TEMPLATE))); return false; } String scripts = getScripts(); if (scripts != null) { String[] scriptsNames = scripts.split(":"); for (String scriptName : scriptsNames) { final DeploymentScriptTypes n = DeploymentScriptTypes .byName(scriptName.trim()); if (!"all".equals(scriptName) && n == null) { getLogger() .error(MessageFormat .format("Cannot create a project. Script with name {0} cannot be found", scriptName)); return false; } } } boolean create = false; if (template == TemplateApplications.ZF2) { // clone zf2 skeleton application create = cloneRepository(template.getBasePath(), destinationFolder); if (create) { cloneGitModules(destinationFolder); project.update(scripts); } } else { create = project.create(getName(), getTemplate(), scripts); } if (create) { getLogger().info( "Project resources were created successfully for " + getName() + " under " + getDestination()); } return create; } return false; } public boolean cloneRepository(String repo, File dir) { CloneCommand clone = new CloneCommand(); clone.setURI(repo); clone.setRemote(Constants.DEFAULT_REMOTE_NAME); clone.setDirectory(dir); clone.setProgressMonitor(new TextProgressMonitor(new PrintWriter( System.out))); getLogger().info( MessageFormat.format("Cloning into {0}...", dir.getName())); try { clone.call(); } catch (JGitInternalException e) { delete(dir); getLogger().error(e); return false; } catch (InvalidRemoteException e) { delete(dir); getLogger().error(e); return false; } catch (TransportException e) { delete(dir); getLogger().error(e); return false; } catch (GitAPIException e) { delete(dir); getLogger().error(e); return false; } return true; } private void cloneGitModules(File destinationFolder) { File gitModules = new File(destinationFolder, ".gitmodules"); if (gitModules.exists()) { Map<String, String> modules = parseGitModules(gitModules); Set<String> paths = modules.keySet(); for (String path : paths) { String url = modules.get(path); File destinationPath = new File(destinationFolder, path); cloneRepository(url, destinationPath); cloneGitModules(destinationPath); } } } private Map<String, String> parseGitModules(File file) { Map<String, String> modules = new HashMap<String, String>(); List<String> lines = null; try { lines = readGitModules(file); } catch (IOException e) { getLogger().error( MessageFormat.format( "Error during parsing Git modules from {0}", file.getAbsolutePath())); } if (lines != null) { String path = null; String url = null; for (String line : lines) { if (line.startsWith("url")) { url = getEntryValue(line); } else if (line.startsWith("path")) { path = getEntryValue(line); } if (url != null && path != null) { modules.put(path, url); path = null; url = null; } } } return modules; } private List<String> readGitModules(File file) throws IOException { List<String> lines = new ArrayList<String>(); BufferedReader reader = null; try { reader = new BufferedReader(new FileReader(file)); String line = null; while ((line = reader.readLine()) != null) { lines.add(line.trim()); } } finally { if (reader != null) { reader.close(); } } return lines; } private String getEntryValue(String entry) { String[] parts = entry.split("="); if (parts.length == 2) { return parts[1].trim(); } return null; } /** * If nest is on, resolve the nested destination folder * * @param destination2 * @param nest2 * @return */ private File resolveDestination(String destination, String name) { File projectRoot = new File(destination, name); /* * if (!projectRoot.exists()) { final boolean mkdir = * projectRoot.mkdir(); if (!mkdir) { return null; } } */ return projectRoot; } private boolean doOverwite(File destination) { if (destination != null && destination.exists()) { while (true) { String question = "File " + destination.getAbsolutePath() + " already exists. Do you want to overwrite it [y:yes][n:no]?: "; String answer = String.valueOf(System.console().readLine( question)); if ("y".equalsIgnoreCase(answer)) { delete(destination); return true; } else if ("n".equalsIgnoreCase(answer)) { return false; } } } return true; } private boolean delete(File file) { if (file.isDirectory()) { String[] children = file.list(); for (int i = 0; i < children.length; i++) { boolean result = delete(new File(file, children[i])); if (!result) { return false; } } } return file.delete(); } }