package com.hubspot.blazar.command;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Guice;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.hubspot.blazar.base.GitInfo;
import com.hubspot.blazar.base.ModuleDiscoveryResult;
import com.hubspot.blazar.config.BlazarConfigurationWrapper;
import com.hubspot.blazar.data.service.DependenciesService;
import com.hubspot.blazar.discovery.ModuleDiscoveryHandler;
import com.hubspot.blazar.guice.BaseCommandModule;
import io.dropwizard.cli.ConfiguredCommand;
import io.dropwizard.setup.Bootstrap;
import net.sourceforge.argparse4j.inf.Namespace;
public class VersionBackFillCommand extends ConfiguredCommand<BlazarConfigurationWrapper> {
private static String COMMAND_NAME = "version_backfill";
private static String COMMAND_DESC = "Finds projects with no version data for their dependencies, and updates their versions";
private static final Logger LOG = LoggerFactory.getLogger(VersionBackFillCommand.class);
private final ExecutorService executorService;
@Inject
public VersionBackFillCommand() {
super(COMMAND_NAME, COMMAND_DESC);
this.executorService = Executors.newFixedThreadPool(10);
}
@Override
protected void run(Bootstrap<BlazarConfigurationWrapper> bootstrap,
Namespace namespace,
BlazarConfigurationWrapper configuration) throws Exception {
Injector injector = Guice.createInjector(new BaseCommandModule(bootstrap, configuration));
try {
ModuleDiscoveryHandler moduleDiscoveryHandler = injector.getInstance(ModuleDiscoveryHandler.class);
DependenciesService dependenciesService = injector.getInstance(DependenciesService.class);
Set<GitInfo> toBeReDiscovered = dependenciesService.getBranchesWithNonVersionedDependencies();
Set<GitInfo> failed = new HashSet<>();
Map<GitInfo, Future<Boolean>> futureMap = new HashMap<>();
for (GitInfo branch : toBeReDiscovered) {
Task task = new Task(branch, moduleDiscoveryHandler);
Future<Boolean> future = executorService.submit(task);
futureMap.put(branch, future);
}
for (Map.Entry<GitInfo, Future<Boolean>> entry : futureMap.entrySet()) {
handleResult(failed, entry.getKey(), entry.getValue());
}
LOG.info("Failed to process the following branches {}", failed);
} finally {
executorService.shutdownNow();
}
}
private class Task implements Callable<Boolean> {
private final GitInfo branch;
private final ModuleDiscoveryHandler moduleDiscoveryHandler;
Task(GitInfo branch, ModuleDiscoveryHandler moduleDiscoveryHandler) {
this.branch = branch;
this.moduleDiscoveryHandler = moduleDiscoveryHandler;
}
@Override
public Boolean call() throws Exception {
LOG.info("Starting to process gitInfo {}", branch.toString());
try {
ModuleDiscoveryResult result = moduleDiscoveryHandler.updateModules(branch, true);
LOG.info("Got Discovery result: {}", result);
return true;
} catch (IOException e) {
LOG.info("Failed to discover branch {}", branch.toString(), e);
return false;
}
}
}
private void handleResult(Set<GitInfo> failed, GitInfo branch, Future<Boolean> future) {
boolean success;
LOG.info("Collecting future for branch {}", branch.toString());
try {
success = future.get();
} catch (Exception e) {
success = false;
LOG.error("Exception while processing branch {}", branch, e);
}
if (success) {
LOG.info("Completed re-discovery of {}", branch.toString());
} else {
LOG.info("Failed to process branch {}", branch.toString());
failed.add(branch);
}
}
}