package br.uff.ic.dyevc.utils; //~--- non-JDK imports -------------------------------------------------------- import br.uff.ic.dyevc.exception.DyeVCException; import br.uff.ic.dyevc.exception.ServiceException; import br.uff.ic.dyevc.model.MonitoredRepositories; import br.uff.ic.dyevc.model.MonitoredRepository; import br.uff.ic.dyevc.model.topology.RepositoryFilter; import br.uff.ic.dyevc.model.topology.RepositoryInfo; import br.uff.ic.dyevc.persistence.TopologyDAO; import br.uff.ic.dyevc.tools.vcs.git.GitConnector; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.URIish; //~--- JDK imports ------------------------------------------------------------ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; /** * Conversion between MonitoredRepository and RepositoryInfo * * @author Cristiano */ public class RepositoryConverter { private final MonitoredRepository monitoredRepository; private final TopologyDAO topologyDAO; private final ArrayList<RepositoryInfo> relatedNew; private String relatedSystem; private final RepositoryInfo info; private boolean processed; private final HashMap<URIish, String> uriishToIdMap; /** * Constructs ... * * @param monitoredRepository */ public RepositoryConverter(MonitoredRepository monitoredRepository) { this.topologyDAO = new TopologyDAO(); this.relatedNew = new ArrayList<RepositoryInfo>(); this.relatedSystem = monitoredRepository.getSystemName(); this.monitoredRepository = monitoredRepository; this.processed = false; this.info = new RepositoryInfo(); this.uriishToIdMap = new HashMap<URIish, String>(); info.setId(monitoredRepository.getId()); info.setSystemName(monitoredRepository.getSystemName()); info.setCloneName(monitoredRepository.getName()); info.setClonePath(monitoredRepository.getNormalizedCloneAddress()); info.setHostName(SystemUtils.getLocalHostname()); info.setLastChanged(monitoredRepository.getLastChanged()); } public RepositoryInfo toRepositoryInfo() throws DyeVCException { if (!processed) { initialize(); } return info; } private void initialize() throws DyeVCException { verifyRelationships(); processed = true; } public String getRelatedSystem() throws DyeVCException { if (!processed) { initialize(); } return relatedSystem; } /** * Returns the repositories related to this one that do not previously exist * in the database * * @return The list of non previously existing related repositories * @throws DyeVCException */ public ArrayList<RepositoryInfo> getRelatedNewList() throws DyeVCException { if (!processed) { initialize(); } return relatedNew; } /** * Verifies the relations between the converted repository info and other * clones, pushing to or pulling from them. The relations are discovered by * looking at the git configuration file * * @throws DyeVCException * @throws UnknownHostException */ private void verifyRelationships() throws DyeVCException { if (!GitConnector.isValidRepository(monitoredRepository.getCloneAddress())) { throw new DyeVCException("<" + monitoredRepository.getCloneAddress() + "> is not a valid repository path."); } List<RemoteConfig> configs = monitoredRepository.getConnection().getRemoteConfigs(); for (RemoteConfig config : configs) { List<URIish> pushUris = config.getPushURIs(); int pushUrisSize = pushUris.size(); boolean createPushUris = pushUrisSize == 0; for (URIish pushUri : config.getPushURIs()) { addRelationship(pushUri, true, false); } for (URIish uri : config.getURIs()) { addRelationship(uri, createPushUris, true); } } } /** * Finds out the clone name of a referenced repository. If repository is not * local, tries to find this information in the database. * * @param uri The URIish that points to this repository * @param createOnlyPushRelation If true, create only a PushesTo * relationship. Otherwise, create both PushesTo and PullsFrom relationships * @throws ServiceException */ private void addRelationship(URIish uri, boolean createPushUri, boolean createPullUri) throws ServiceException { String id; if (uriishToIdMap.containsKey(uri)) { id = uriishToIdMap.get(uri); } else { id = getIdFromUri(uri); uriishToIdMap.put(uri, id); } if (createPushUri) { info.addPushesTo(id); } if (createPullUri) { info.addPullsFrom(id); } } /** * Gets the id of a repository from an URIIsh object. If id cannot be identified, than creates a new repository. * @param uri The URIIsh to be used to find out the repository id * @return The id corresponding to the specified URIIsh * @throws ServiceException */ private String getIdFromUri(URIish uri) throws ServiceException { String id; String scheme = uri.getScheme(); String hostName = uri.getHost(); boolean isLocal = ((scheme == null) && (hostName == null)) || ((hostName != null) && (hostName.equalsIgnoreCase("localhost") || hostName.equals("127.0.0.1"))); if (isLocal) { hostName = SystemUtils.getLocalHostname(); } // Takes out leading slashes and changes double backslashes by slashes String strippedPath = StringUtils.normalizePath(uri.getPath()); // Remove ".git" in the end of the path if (strippedPath.endsWith(GitConnector.GIT_DIR)) { strippedPath = strippedPath.substring(0, strippedPath.lastIndexOf(GitConnector.GIT_DIR)); } // Checks if there is a monitored repository to get the clone name from MonitoredRepository rep = MonitoredRepositories.getMonitoredProjectByPath(uri.getPath()); if (rep != null) { id = rep.getId(); if (!rep.getSystemName().equals(info.getSystemName())) { relatedSystem = rep.getSystemName(); } } else { // If not, checks if there is a repository in the database to get the clone name from RepositoryFilter filter = new RepositoryFilter(); filter.setHostName(hostName); filter.setClonePath(strippedPath); List<RepositoryInfo> listRepo = topologyDAO.getRepositoriesByQuery(filter); if (!listRepo.isEmpty()) { id = listRepo.get(0).getId(); String system = listRepo.get(0).getSystemName(); if (!system.equals(info.getSystemName())) { relatedSystem = system; } } else { // if not, adds a new repository that is referenced but not monitored String cloneName = SystemUtils.getFilenameOrLastPath(strippedPath); id = addNewRelatedRepository(hostName, cloneName, strippedPath).getId(); } } return id; } /** * Adds a remote repository (toProcess) to be included in the database. * * @param hostName The hostName of the remote repository * @param strippedPath The Path to the remote repository (also used as its * clone name) */ private RepositoryInfo addNewRelatedRepository(String hostName, String cloneName, String strippedPath) { // Creates a new repository info to be sent to database. RepositoryInfo toProcess = new RepositoryInfo(); toProcess.setId(StringUtils.generateRepositoryId()); toProcess.setSystemName(info.getSystemName()); toProcess.setHostName(hostName); toProcess.setClonePath(strippedPath); toProcess.setCloneName(cloneName); relatedNew.add(toProcess); return toProcess; } /** * Returns the repository unique id related to the specified uri * @param uri The uri of the repository to return the id. The URIish is the one set in git's config file. * @return The repository id that maps to the specified uri. * @throws DyeVCException */ public String mapUriToRepositoryId(URIish uri) throws DyeVCException { if (!processed) { initialize(); } return uriishToIdMap.get(uri); } }