package com.cadrlife.devsearch.agent.service; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collection; import java.util.List; import com.cadrlife.devsearch.agent.UpdateScope; import com.cadrlife.devsearch.domain.Project; import com.google.common.base.Function; import com.google.common.base.Strings; import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; import com.google.common.io.ByteStreams; import com.google.common.io.Files; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import org.apache.commons.lang.NotImplementedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class RepoService { private String repoName = ""; private ListeningExecutorService executorService; public abstract List <Project> findAllProjects(); private static final Logger LOG = LoggerFactory.getLogger(RepoService.class); protected Path checkoutRootPath; public abstract void updateProject(File file, Project projectName); public abstract String getSourceType(); // Override when more needs to happen public List<Project> findProjectsByName(String projectName) { Path checkoutPath = checkoutRootPath.resolve(getRepoName()).resolve(projectName); return Lists.newArrayList(new Project().setRepo(getRepoName()).setName(projectName).setCheckoutPath(checkoutPath)); } protected final List<Project> findProjectsByAnyName(Collection<String> projectNames) { return FluentIterable.from(projectNames).transformAndConcat(new ProjectNameToProjectsFunction()).toList(); } public String getRepoName() { return repoName; } public RepoService setRepoName(String repoName) { this.repoName = repoName; return this; } protected void saveStringToFile(String source, File localFile) throws IOException { Files.createParentDirs(localFile); ByteStreams.write(source.getBytes(Charset.defaultCharset()), Files.newOutputStreamSupplier(localFile)); } protected void saveStreamToFile(InputStream source, File localFile) throws IOException { Files.createParentDirs(localFile); ByteStreams.copy(source, Files.newOutputStreamSupplier(localFile)); } public Iterable<ListenableFuture<Project>> pullRepo(UpdateScope updateScope) { List<ListenableFuture<Project>> projectFutures = new ArrayList<>(); for (final Project project : findMatchingProjects(updateScope)) { String projectName = project.getName(); if (updateScope.getExcluded().contains(projectName)) { LOG.info("Project {} excluded on command line. Skipping.", projectName); } else { if (!project.hasRepo()) { project.setRepo(updateScope.getRepoName()); } Path repoCheckoutDir = checkoutRootPath.resolve(project.getRepo()); repoCheckoutDir.toFile().mkdirs(); final Path projectCheckoutDir = repoCheckoutDir.resolve(projectName); LOG.info("projectCheckoutDir is {}", projectCheckoutDir); project.setCheckoutPath(projectCheckoutDir); projectFutures.add(scheduleProjectPull(project)); // projectHandler.handleProject(project); } } // Project project = findProjectsByName(updateScope.getProjectName()); // projects.add(project); // // // if (!project.hasRepo()) { // project.setRepo(updateScope.getRepoName()); // } // Path repoCheckoutDir = checkoutRootPath.resolve(project.getRepo()); // // Path projectCheckoutDir = repoCheckoutDir.resolve(updateScope.getProjectName()); // LOG.info("projectCheckoutDir is {}", projectCheckoutDir); // project.setCheckoutPath(projectCheckoutDir); // updateWithRetry(project, projectCheckoutDir); // projectHandler.handleProject(project); return projectFutures; } private ListenableFuture<Project> scheduleProjectPull(final Project project) { return executorService.submit(new Runnable() { @Override public void run() { updateWithRetry(project, project.getCheckoutPath()); } }, project); } private List<Project> findMatchingProjects(UpdateScope scope) { if (scope.isAllProjects()) { return findAllProjects(); } return findProjectsByName(scope.getProjectName()); } public void setCheckoutRootPath(Path checkoutRootPath) { this.checkoutRootPath = checkoutRootPath; } private void updateWithRetry(Project project, Path projectCheckoutDir) { try { updateProject(projectCheckoutDir.toFile(), project); } catch (Exception e) { LOG.error("Error updating {}, retrying once", project.getName(), e); updateProject(projectCheckoutDir.toFile(), project); } } public void pushRepo(Project project) { throw new NotImplementedException("No push action defined for repo " + project.getRepo()); } public void setExecutorService(ListeningExecutorService executorService) { this.executorService = executorService; } private final class ProjectNameToProjectsFunction implements Function<String,List<Project>> { @Override public List<Project> apply(String input) { return findProjectsByName(input); } } }