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);
}
}
}