| package com.intellij.lang.javascript.boilerplate; |
| |
| import com.google.common.base.Charsets; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.io.Files; |
| import com.google.gson.JsonArray; |
| import com.google.gson.JsonElement; |
| import com.google.gson.JsonObject; |
| import com.google.gson.JsonParser; |
| import com.intellij.openapi.application.ApplicationManager; |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.platform.templates.github.GeneratorException; |
| import com.intellij.platform.templates.github.GithubTagInfo; |
| import com.intellij.util.ui.UIUtil; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.io.File; |
| import java.io.IOException; |
| |
| /** |
| * @author Sergey Simonchik |
| */ |
| public class GithubTagListProvider { |
| |
| private static final Logger LOG = Logger.getInstance(GithubTagListProvider.class); |
| |
| private final String myUserName; |
| private final String myRepositoryName; |
| |
| public GithubTagListProvider(@NotNull String userName, @NotNull String repositoryName) { |
| myUserName = userName; |
| myRepositoryName = repositoryName; |
| } |
| |
| @Nullable |
| public ImmutableSet<GithubTagInfo> getCachedTags() { |
| ApplicationManager.getApplication().assertIsDispatchThread(); |
| File cacheFile = getTagsCacheFile(); |
| if (cacheFile.isFile()) { |
| try { |
| ImmutableSet<GithubTagInfo> tags = readTagsFromFile(cacheFile); |
| LOG.info(getGeneratorName() + "tag info list has been successfully read from cache file " + cacheFile.getAbsolutePath()); |
| return tags; |
| } catch (GeneratorException e) { |
| LOG.warn("Can't read cache file " + cacheFile.getAbsolutePath(), e); |
| } |
| } |
| return null; |
| } |
| |
| public void updateTagListAsynchronously(@NotNull final GithubProjectGeneratorPeer peer) { |
| Runnable action = createUpdateTagListAction(peer); |
| if (ApplicationManager.getApplication().isUnitTestMode()) { |
| action.run(); |
| } |
| else { |
| ApplicationManager.getApplication().executeOnPooledThread(action); |
| } |
| } |
| |
| private Runnable createUpdateTagListAction(@NotNull final GithubProjectGeneratorPeer peer) { |
| return new Runnable() { |
| @Override |
| public void run() { |
| final String[] urls = formatTagListDownloadUrls(); |
| String firstErrorMessage = null; |
| for (String url : urls) { |
| String errorMessage; |
| try { |
| final ImmutableSet<GithubTagInfo> tags = fetchGithubTagsByUrl(url); |
| LOG.info(getGeneratorName() + "Cache has been successfully updated"); |
| UIUtil.invokeLaterIfNeeded(new Runnable() { |
| @Override |
| public void run() { |
| peer.onTagsUpdated(tags); |
| } |
| }); |
| return; |
| } |
| catch (IOException e) { |
| errorMessage = "Can not fetch tags from " + url; |
| LOG.warn(getGeneratorName() + errorMessage, e); |
| } |
| catch (GeneratorException e) { |
| errorMessage = "Malformed JSON received from " + url; |
| LOG.warn(getGeneratorName() + errorMessage, e); |
| } |
| if (firstErrorMessage == null) { |
| firstErrorMessage = errorMessage; |
| } |
| } |
| if (firstErrorMessage != null) { |
| peer.onTagsUpdateError(firstErrorMessage); |
| } |
| } |
| }; |
| } |
| |
| private ImmutableSet<GithubTagInfo> fetchGithubTagsByUrl(@NotNull final String url) throws IOException, GeneratorException { |
| LOG.info(getGeneratorName() + "starting cache update from " + url + " ..."); |
| File cacheFile = getTagsCacheFile(); |
| GithubDownloadUtil.downloadAtomically(null, url, cacheFile, myUserName, myRepositoryName); |
| return readTagsFromFile(cacheFile); |
| } |
| |
| private String getGeneratorName() { |
| return "[" + myUserName + "/" + myRepositoryName + "] "; |
| } |
| |
| @NotNull |
| private ImmutableSet<GithubTagInfo> readTagsFromFile(@NotNull File file) throws GeneratorException { |
| final String content; |
| try { |
| content = Files.toString(file, Charsets.UTF_8); |
| } |
| catch (IOException e) { |
| throw new GeneratorException("Can not read '" + file.getAbsolutePath() + "'!", e); |
| } |
| try { |
| return parseContent(content); |
| } catch (GeneratorException e) { |
| String message = String.format("%s parsing version list failed: %s\n%s", |
| getGeneratorName(), |
| e.getMessage(), |
| content); |
| LOG.info(message, e); |
| throw e; |
| } |
| } |
| |
| @NotNull |
| private static ImmutableSet<GithubTagInfo> parseContent(@NotNull String tagFileContent) throws GeneratorException { |
| if (tagFileContent.trim().isEmpty()) { |
| throw new GeneratorException("Can not parse fetched version list: got empty response"); |
| } |
| final JsonElement jsonElement; |
| try { |
| JsonParser jsonParser = new JsonParser(); |
| jsonElement = jsonParser.parse(tagFileContent); |
| } catch (Exception e) { |
| throw new GeneratorException("Can not parse fetched version list: malformed JSON was received"); |
| } |
| return toGithubTagList(jsonElement); |
| } |
| |
| @NotNull |
| private static ImmutableSet<GithubTagInfo> toGithubTagList(@NotNull JsonElement jsonElement) throws GeneratorException { |
| if (jsonElement instanceof JsonArray) { |
| JsonArray array = (JsonArray) jsonElement; |
| ImmutableSet.Builder<GithubTagInfo> tags = ImmutableSet.builder(); |
| for (JsonElement element : array) { |
| if (element instanceof JsonObject) { |
| JsonObject obj = (JsonObject) element; |
| JsonElement nameElement = obj.get("name"); |
| String name = null; |
| if (nameElement != null) { |
| name = nameElement.getAsString(); |
| } |
| String zipball = null; |
| JsonElement zipballElement = obj.get("zipball_url"); |
| if (zipballElement != null) { |
| zipball = zipballElement.getAsString(); |
| } |
| if (name != null && zipball != null) { |
| tags.add(new GithubTagInfo(name, zipball)); |
| } |
| } |
| else { |
| throw new GeneratorException("Unexpected child element " + element.getClass().getName()); |
| } |
| } |
| return tags.build(); |
| } |
| else { |
| throw new GeneratorException("jsonElement is expected be instance of " + JsonArray.class.getName()); |
| } |
| } |
| |
| @NotNull |
| private File getTagsCacheFile() { |
| File dir = GithubDownloadUtil.getCacheDir(myUserName, myRepositoryName); |
| return new File(dir, "tags.json"); |
| } |
| |
| @NotNull |
| private String[] formatTagListDownloadUrls() { |
| return new String[] { |
| "https://api.github.com/repos/" + myUserName + "/" + myRepositoryName + "/tags", |
| "http://download.jetbrains.com/idea/project_templates/github-tags/" + myUserName + "-" + myRepositoryName + "-tags.json" |
| }; |
| } |
| |
| } |