package org.bndtools.templating.jgit; import java.net.URI; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map.Entry; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.bndtools.templating.Template; import org.bndtools.templating.TemplateLoader; import org.osgi.framework.Constants; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferenceCardinality; import org.osgi.service.component.annotations.ReferencePolicyOption; import org.osgi.util.function.Function; import org.osgi.util.promise.Promise; import org.osgi.util.promise.Promises; import aQute.bnd.header.Attrs; import aQute.bnd.header.Parameters; import aQute.lib.base64.Base64; import aQute.service.reporter.Reporter; @Component(name = "org.bndtools.core.templating.workspace.github", property = { Constants.SERVICE_DESCRIPTION + "=Load workspace templates from GitHub repositories" }) public class GitHubWorkspaceTemplateLoader implements TemplateLoader { private static final String TEMPLATE_TYPE = "workspace"; private final Cache cache = new Cache(); private ExecutorService executor; @Reference(cardinality = ReferenceCardinality.OPTIONAL, policyOption = ReferencePolicyOption.GREEDY) void setExecutorService(ExecutorService executor) { this.executor = executor; } @Activate void activate() { if (executor == null) executor = Executors.newCachedThreadPool(); } @Override public Promise<List<Template>> findTemplates(String type, Reporter reporter) { if (!TEMPLATE_TYPE.equals(type)) return Promises.resolved(Collections.<Template> emptyList()); List<Promise<Template>> promises = new LinkedList<>(); Parameters githubRepos = new GitRepoPreferences().getGithubRepos(); for (Entry<String,Attrs> entry : githubRepos.entrySet()) { final String repo = GitRepoPreferences.removeDuplicateMarker(entry.getKey()); final Attrs attribs = entry.getValue(); try { final GitHub gitHub = new GitHub(cache, executor); promises.add(gitHub.loadRepoDetails(repo).map(new Function<GithubRepoDetailsDTO,Template>() { @Override public Template apply(GithubRepoDetailsDTO detailsDTO) { if (detailsDTO.clone_url == null) throw new IllegalArgumentException("Missing clone URL"); // Generate icon URI from the owner avatar. The s=16 parameter // is added to select a 16x16 icon. URI avatarUri = null; if (detailsDTO.owner.avatar_url != null) avatarUri = URI.create(detailsDTO.owner.avatar_url + "&s=16"); String name = attribs.get("name"); if (name == null) name = repo; String branch = attribs.get("branch"); final GitCloneTemplateParams params = new GitCloneTemplateParams(); params.cloneUrl = detailsDTO.clone_url; if (branch != null) params.branch = branch; else params.branch = "origin/" + detailsDTO.default_branch; params.name = name; params.category = "GitHub"; params.iconUri = avatarUri; if (detailsDTO.html_url != null) { params.helpUri = createHelpUri(repo, detailsDTO.html_url); } return new GitCloneTemplate(params); } })); } catch (Exception e) { reporter.exception(e, "Error loading template from Github repository %s", repo); } } return Promises.all(promises); } private static URI createHelpUri(String repoName, String linkUri) { try { String formText = String.format("<form><p>This is a GitHub template using the repository %s. See the <a href='%s'>project homepage</a> for more information.</p></form>", repoName, new URI(linkUri)); String encodedFormText = Base64.encodeBase64(formText.getBytes("UTF-8")); return new URI("data:text/xml;base64," + encodedFormText); } catch (Exception e) { return null; } } }