package de.hub.srcrepo.emffrag; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EPackage; import org.eclipse.equinox.app.IApplication; import org.eclipse.equinox.app.IApplicationContext; import org.eclipse.gmt.modisco.java.emffrag.metadata.JavaPackage; import de.hub.emffrag.EmfFragActivator; import de.hub.emffrag.FObject; import de.hub.emffrag.Fragmentation; import de.hub.emffrag.FragmentationImpl; import de.hub.emffrag.datastore.DataStoreImpl; import de.hub.emffrag.datastore.IBaseDataStore; import de.hub.emffrag.datastore.IDataStore; import de.hub.emffrag.mongodb.EmfFragMongoDBActivator; import de.hub.emffrag.mongodb.MongoDBDataStore; import de.hub.srcrepo.GitSourceControlSystem; import de.hub.srcrepo.IRepositoryModelVisitor; import de.hub.srcrepo.ISourceControlSystem; import de.hub.srcrepo.ISourceControlSystem.SourceControlException; import de.hub.srcrepo.RepositoryModelFlatTraversal; import de.hub.srcrepo.RepositoryModelRevisionCheckoutVisitor; import de.hub.srcrepo.RepositoryModelTraversal; import de.hub.srcrepo.SrcRepoActivator; import de.hub.srcrepo.repositorymodel.RepositoryModel; import de.hub.srcrepo.repositorymodel.emffrag.metadata.RepositoryModelPackage; public class EmfFragSrcRepoImport implements IApplication { public interface RepositoryModelVisitorFactory { public IRepositoryModelVisitor createRepositoryModelVisitor(); } public static class Configuration { private final ISourceControlSystem scs; private final File workingDirectory; private final URI modelURI; private String repositoryURL = null; private int fragmentCacheSize = 100; private boolean skipSourceCodeImport = false; private boolean checkOutWithoutImport = false; private boolean useFlatTraversal = false; private boolean useCGit = false; private RepositoryModelVisitorFactory visitorFactory = null; public Configuration(ISourceControlSystem scs, File workingDirectory, URI modelURI) { super(); this.scs = scs; this.workingDirectory = workingDirectory; this.modelURI = modelURI; } public Configuration repositoryURL(String repositoryURL) { this.repositoryURL = repositoryURL; return this; } public Configuration fragmentCacheSize(int fragmentCacheSize) { this.fragmentCacheSize = fragmentCacheSize; return this; } public Configuration skipSourceCodeImport() { this.skipSourceCodeImport = true; return this; } public Configuration checkOutWithoutImport() { this.checkOutWithoutImport = true; return this; } public Configuration useFlatTraversal() { this.useFlatTraversal = true; return this; } public Configuration useCGit() { this.useCGit = true; return this; } public Configuration withRepositoryModelVisitorFactory(RepositoryModelVisitorFactory visitorFactory) { this.visitorFactory = visitorFactory; return this; } } public static class GitConfiguration extends Configuration { public GitConfiguration(File workingDirectory, URI modelURI) { super(new GitSourceControlSystem(), workingDirectory, modelURI); } } private Options createOptions() { Options options = new Options(); options.addOption(Option.builder(). longOpt("clone"). desc("Clone the repository, old local copy is removed if it exists."). hasArg(). argName("url").build()); options.addOption(Option.builder(). longOpt("fragments-cache"). desc("Number of cached fragments. Default is 1000."). hasArg().argName("size").build()); options.addOption(Option.builder(). longOpt("checkout-without-import"). desc("Just checkout each rev, but do not import via MoDisco.").build()); options.addOption(Option.builder(). longOpt("use-flat-traversal"). desc("Traverse the repository rev by rev not traversining branches.").build()); options.addOption(Option.builder(). longOpt("use-c-git"). desc("Use regular git shell commands and not jGit.").build()); return options; } private boolean checkArgs(CommandLine cl) { return cl.getArgList().size() == 2 && (!cl.hasOption("log") || (Integer.parseInt(cl.getOptionValue("log")) >= 0 && Integer.parseInt(cl.getOptionValue("log")) <=4)) && (!cl.hasOption("fragments-cache") || Integer.parseInt(cl.getOptionValue("fragments-cache")) > 0); } private void printUsage() { new HelpFormatter().printHelp("eclipse ... [options] working-copy-path data-base-uri", createOptions()); } @Override public Object start(IApplicationContext context) throws Exception { // ensure loading of plug-ins EmfFragActivator.class.getName(); SrcRepoActivator.class.getName(); EmfFragMongoDBActivator.class.getName(); // checking command line options final Map<?,?> args = context.getArguments(); final String[] appArgs = (String[]) args.get("application.args"); CommandLineParser cliParser = new DefaultParser(); Options options = createOptions(); CommandLine commandLine = null; try { commandLine = cliParser.parse(options, appArgs); } catch (Exception e) { printUsage(); return IApplication.EXIT_OK; } if (!checkArgs(commandLine)) { printUsage(); return IApplication.EXIT_OK; } URI modelURI = URI.createURI((String)commandLine.getArgList().get(1)); File workingDirectory = new File((String)commandLine.getArgList().get(0)); Configuration config = new Configuration(new GitSourceControlSystem(), workingDirectory, modelURI); if (commandLine.hasOption("clone")) { config.repositoryURL(commandLine.getOptionValue("clone")); } if (commandLine.hasOption("fragments-cache")) { config.fragmentCacheSize(Integer.parseInt(commandLine.getOptionValue("fragments-cache"))); } if (commandLine.hasOption("checkout-without-import")) { config.checkOutWithoutImport(); } if (commandLine.hasOption("use-flat-traversal")) { config.useFlatTraversal(); } if (commandLine.hasOption("use-c-git")) { config.useCGit(); } importRepository(config); return IApplication.EXIT_OK; } public static Fragmentation openFragmentation(Configuration config, boolean dropIfExists) { IBaseDataStore baseDataStore = null; if ("mongodb".equals(config.modelURI.scheme())) { MongoDBDataStore mongoDbBaseDataStore = new MongoDBDataStore(config.modelURI.authority(), config.modelURI.port(), config.modelURI.path().substring(1), dropIfExists); baseDataStore = mongoDbBaseDataStore; } else { throw new RuntimeException("Unknown scheme " + config.modelURI.scheme()); } IDataStore dataStore = new DataStoreImpl(baseDataStore, config.modelURI); List<EPackage> packages = new ArrayList<EPackage>(); packages.add(JavaPackage.eINSTANCE); packages.add(RepositoryModelPackage.eINSTANCE); Fragmentation fragmentation = new FragmentationImpl(packages, dataStore, config.fragmentCacheSize); return fragmentation; } public static void closeFragmentation(Configuration config, Fragmentation fragmentation) { fragmentation.close(); fragmentation.getDataStore().close(); } public static void importRepository(Configuration config) { SrcRepoActivator.INSTANCE.useCGit = config.useCGit; // create fragmentation Fragmentation fragmentation = openFragmentation(config, true); // create necessary models RepositoryModelPackage repositoryModelPackage = RepositoryModelPackage.eINSTANCE; JavaPackage javaModelPackage = JavaPackage.eINSTANCE; RepositoryModel repositoryModel = null; repositoryModel = repositoryModelPackage.getRepositoryModelFactory().createRepositoryModel(); // creating working copy try { if (config.repositoryURL != null) { SrcRepoActivator.INSTANCE.info("Cloning " + config.repositoryURL + " into " + config.workingDirectory + "."); config.scs.createWorkingCopy(config.workingDirectory, config.repositoryURL, false); } else { config.scs.setWorkingCopy(config.workingDirectory); } } catch (SourceControlException e) { SrcRepoActivator.INSTANCE.error("Could not create working copy.", e); } // importing rev model SrcRepoActivator.INSTANCE.info("Importing into " + config.modelURI + " from " + config.workingDirectory + "."); try { config.scs.importRevisions(repositoryModel); } catch (SourceControlException e) { SrcRepoActivator.INSTANCE.error("Could not import the revision model.", e); return; } fragmentation.setRoot((FObject)repositoryModel); repositoryModel = fragmentation.getRoot(); // importing source code IRepositoryModelVisitor sourceImportVisitor = null; if (config.visitorFactory != null) { sourceImportVisitor = config.visitorFactory.createRepositoryModelVisitor(); } else { if (config.checkOutWithoutImport) { sourceImportVisitor = new RepositoryModelRevisionCheckoutVisitor(config.scs, repositoryModel); } else { sourceImportVisitor = new EmffragMoDiscoImportRepositoryModelVisitor(config.scs, repositoryModel, javaModelPackage); } } if (!config.skipSourceCodeImport) { if (config.useFlatTraversal) { RepositoryModelFlatTraversal.traverse(repositoryModel, sourceImportVisitor); } else { RepositoryModelTraversal.traverse(repositoryModel, sourceImportVisitor); } } try { SrcRepoActivator.INSTANCE.info("Import complete. Saving and closing everything."); config.scs.close(); sourceImportVisitor.close(repositoryModel); } catch (Exception e) { SrcRepoActivator.INSTANCE.warning("Exception during cleanup and closing.", e); } finally { closeFragmentation(config, fragmentation); SrcRepoActivator.INSTANCE.info("Import done."); } } @Override public void stop() { } }