]> source.dussan.org Git - sonarqube.git/blob
7e95d397679f545278b367ec1aee7c47dee3052e
[sonarqube.git] /
1 /*
2  * Sonar, open source software quality management tool.
3  * Copyright (C) 2009 SonarSource SA
4  * mailto:contact AT sonarsource DOT com
5  *
6  * Sonar is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 3 of the License, or (at your option) any later version.
10  *
11  * Sonar is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Sonar; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
19  */
20 package org.sonar.updatecenter.deprecated;
21
22 import org.apache.commons.io.FileUtils;
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.maven.artifact.Artifact;
25 import org.apache.maven.artifact.factory.ArtifactFactory;
26 import org.apache.maven.artifact.metadata.ArtifactMetadataSource;
27 import org.apache.maven.artifact.repository.ArtifactRepository;
28 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
29 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
30 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
31 import org.apache.maven.artifact.resolver.ArtifactResolutionRequest;
32 import org.apache.maven.artifact.resolver.ArtifactResolver;
33 import org.apache.maven.artifact.versioning.ArtifactVersion;
34 import org.apache.maven.model.Dependency;
35 import org.apache.maven.model.Developer;
36 import org.apache.maven.project.MavenProject;
37 import org.apache.maven.project.MavenProjectBuilder;
38 import org.codehaus.plexus.ContainerConfiguration;
39 import org.codehaus.plexus.DefaultContainerConfiguration;
40 import org.codehaus.plexus.DefaultPlexusContainer;
41 import org.codehaus.plexus.PlexusContainer;
42 import org.codehaus.plexus.classworlds.ClassWorld;
43 import org.json.simple.JSONArray;
44 import org.json.simple.JSONObject;
45 import org.kohsuke.args4j.CmdLineParser;
46 import org.kohsuke.args4j.Option;
47
48 import java.io.File;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.List;
52
53 /**
54  * @author Evgeny Mandrikov
55  */
56 public class UpdateCenter {
57   // FIXME value set only for debug purposes 
58   @Option(name = "-d")
59   public File outputDirectory = new File("/tmp/site");
60
61   private static final String ARTIFACT_JAR_TYPE = "jar";
62   private static final String ARTIFACT_POM_TYPE = "pom";
63
64   private List<ArtifactRepository> remoteRepositories;
65   private ArtifactRepository localRepository;
66
67   private ArtifactFactory artifactFactory;
68   private ArtifactResolver artifactResolver;
69   private ArtifactMetadataSource metadataSource;
70   private MavenProjectBuilder mavenProjectBuilder;
71
72   private void run() throws Exception {
73     // Init plexus
74     ClassWorld classWorld = new ClassWorld("plexus.core", UpdateCenter.class.getClassLoader());
75     ContainerConfiguration configuration = new DefaultContainerConfiguration().setClassWorld(classWorld);
76     PlexusContainer plexus = new DefaultPlexusContainer(configuration);
77     // Init components
78     artifactFactory = plexus.lookup(ArtifactFactory.class);
79     artifactResolver = plexus.lookup(ArtifactResolver.class);
80     metadataSource = plexus.lookup(ArtifactMetadataSource.class);
81     mavenProjectBuilder = plexus.lookup(MavenProjectBuilder.class);
82     ArtifactRepositoryFactory artifactRepositoryFactory = plexus.lookup(ArtifactRepositoryFactory.class);
83     // Init repositories
84     ArtifactRepositoryPolicy policy = new ArtifactRepositoryPolicy(
85         true,
86         ArtifactRepositoryPolicy.UPDATE_POLICY_DAILY,
87         ArtifactRepositoryPolicy.CHECKSUM_POLICY_WARN
88     );
89     remoteRepositories = Collections.singletonList( // TODO add SonarSource repository with commercial plugins
90         artifactRepositoryFactory.createArtifactRepository(
91             "codehaus",
92             "http://repository.codehaus.org/",
93             new DefaultRepositoryLayout(),
94             policy,
95             policy
96         )
97     );
98     File localRepo = new File(new File(System.getProperty("user.home")), ".m2/repository");
99     localRepository = artifactRepositoryFactory.createArtifactRepository(
100         "local",
101         localRepo.toURI().toURL().toExternalForm(),
102         new DefaultRepositoryLayout(),
103         policy,
104         policy
105     );
106     // Do work
107     JSONObject obj = new JSONObject();
108
109     obj.put("version", "1"); // We can bump this version, when we make incompatible changes
110     obj.put("plugins", resolvePlugins());
111     obj.put("sonar", resolveSonar());
112
113     if (outputDirectory != null) {
114       FileUtils.writeStringToFile(new File(outputDirectory, "update-center.json"), obj.toJSONString());
115     }
116   }
117
118   private JSONArray resolvePlugins() throws Exception {
119     List<String> plugins = FileUtils.readLines(FileUtils.toFile(getClass().getResource("/plugins.txt")));
120
121     String pluginInfoWidgetTemplate = FileUtils.readFileToString(
122         FileUtils.toFile(getClass().getResource("/plugin-info-widget-template.html"))
123     );
124     if (outputDirectory != null) {
125       FileUtils.copyURLToFile(getClass().getResource("/style.css"), new File(outputDirectory, "plugins/style.css"));
126     }
127
128     JSONArray json = new JSONArray();
129     for (String plugin : plugins) {
130       if (plugin.startsWith("#")) {
131         // Skip comments
132         continue;
133       }
134       History<Plugin> history = resolvePluginHistory(plugin);
135       if (history.latest() == null) {
136         System.out.println("WTF? " + plugin);
137         continue;
138       }
139       json.add(history.latest().toJsonObject());
140
141       Plugin latest = history.latest();
142
143       if (outputDirectory != null) {
144         String pluginInfoWidget = StringUtils.replaceEach(
145             pluginInfoWidgetTemplate,
146             new String[]{"%name%", "%version%", "%date%", "%downloadUrl%", "%sonarVersion%", "%issueTracker%", "%sources%", "%license%", "%developers%"},
147             new String[]{
148                 latest.getName(),
149                 latest.getVersion(),
150                 latest.getReleaseDate(),
151                 latest.getDownloadUrl(),
152                 latest.getRequiredSonarVersion(),
153                 formatLink(latest.getIssueTracker()),
154                 formatLink(latest.getSources()),
155                 latest.getLicense() == null ? "Unknown" : latest.getLicense(),
156                 formatDevelopers(latest.getDevelopers())
157             }
158         );
159         FileUtils.writeStringToFile(new File(outputDirectory, "plugins/" +  latest.getKey() + ".html"), pluginInfoWidget);
160       }
161
162       // TODO use logger
163       System.out.println(latest.getName() + " : " + history.getAllVersions() + ", latest " + latest.getVersion());
164     }
165
166     return json;
167   }
168
169   private String formatDevelopers(List<Developer> developers) {
170     if (developers == null) {
171       return "Unknown";
172     }
173     StringBuilder sb = new StringBuilder();
174     for (int i = 0; i < developers.size(); i++) {
175       if (i > 0) {
176         sb.append(", ");
177       }
178       sb.append(developers.get(i).getName());
179     }
180     return sb.toString();
181   }
182
183   private String formatLink(String url) {
184     return StringUtils.isBlank(url) ? "Unknown" : "<a href=\"" + url + "\" target=\"_top\">" + url + "</a>";
185   }
186
187   private JSONObject resolveSonar() throws Exception {
188     Artifact artifact = artifactFactory.createArtifact(
189         "org.codehaus.sonar",
190         "sonar-plugin-api",
191         Artifact.LATEST_VERSION,
192         Artifact.SCOPE_COMPILE,
193         ARTIFACT_JAR_TYPE
194     );
195
196     List<ArtifactVersion> versions = filterSnapshots(
197         metadataSource.retrieveAvailableVersions(artifact, localRepository, remoteRepositories)
198     );
199     History<Sonar> history = new History<Sonar>();
200     for (ArtifactVersion version : versions) {
201       history.addArtifact(version, new Sonar(version.toString()));
202     }
203
204     return history.latest().toJsonObject();
205   }
206
207   private String getDownloadUrl(String groupId, String artifactId, String version) {
208     // FIXME dirty hack
209     return "http://repository.codehaus.org/"
210         + StringUtils.replace(groupId, ".", "/") + "/"
211         + artifactId + "/"
212         + version + "/"
213         + artifactId + "-" + version + "." + ARTIFACT_JAR_TYPE;
214   }
215
216   private History<Plugin> resolvePluginHistory(String id) throws Exception {
217     String groupId = StringUtils.substringBefore(id, ":");
218     String artifactId = StringUtils.substringAfter(id, ":");
219
220     Artifact artifact = artifactFactory.createArtifact(
221         groupId, artifactId, Artifact.LATEST_VERSION, Artifact.SCOPE_COMPILE, ARTIFACT_JAR_TYPE
222     );
223
224     List<ArtifactVersion> versions = filterSnapshots(
225         metadataSource.retrieveAvailableVersions(artifact, localRepository, remoteRepositories)
226     );
227
228     History<Plugin> history = new History<Plugin>();
229     for (ArtifactVersion version : versions) {
230       Plugin plugin = org.sonar.updatecenter.deprecated.Plugin.extractMetadata(resolve(artifact.getGroupId(), artifact.getArtifactId(), version.toString()));
231       history.addArtifact(version, plugin);
232
233       MavenProject project = mavenProjectBuilder.buildFromRepository(
234           artifactFactory.createArtifact(groupId, artifactId, version.toString(), Artifact.SCOPE_COMPILE, ARTIFACT_POM_TYPE),
235           remoteRepositories,
236           localRepository
237       );
238
239       if (plugin.getVersion() == null) {
240         // Legacy plugin - set default values
241         plugin.setKey(project.getArtifactId());
242         plugin.setName(project.getName());
243         plugin.setVersion(project.getVersion());
244
245         String sonarVersion = "1.10"; // TODO Is it minimal version for all extension points ?
246         for (Dependency dependency : project.getDependencies()) {
247           if ("sonar-plugin-api".equals(dependency.getArtifactId())) { // TODO dirty hack
248             sonarVersion = dependency.getVersion();
249           }
250         }
251
252         plugin.setRequiredSonarVersion(sonarVersion);
253         plugin.setHomepage(project.getUrl());
254       }
255       plugin.setDownloadUrl(getDownloadUrl(groupId, artifactId, plugin.getVersion()));
256       // There is no equivalent for following properties in MANIFEST.MF
257       if (project.getIssueManagement() != null) {
258         plugin.setIssueTracker(project.getIssueManagement().getUrl());
259       } else {
260         System.out.println("Unknown Issue Management for " + plugin.getKey() + ":" + plugin.getVersion());
261       }
262       if (project.getScm() != null) {
263         String scmUrl = project.getScm().getUrl();
264         if (StringUtils.startsWith(scmUrl, "scm:")) {
265           scmUrl = StringUtils.substringAfter(StringUtils.substringAfter(scmUrl, ":"), ":");
266         }
267         plugin.setSources(scmUrl);
268       } else {
269         System.out.println("Unknown SCM for " + plugin.getKey() + ":" + plugin.getVersion());
270       }
271       if (project.getLicenses() != null && project.getLicenses().size() > 0) {
272         plugin.setLicense(project.getLicenses().get(0).getName());
273       } else {
274         System.out.println("Unknown License for " + plugin.getKey() + ":" + plugin.getVersion());
275       }
276       if (project.getDevelopers().size() > 0) {
277         plugin.setDevelopers(project.getDevelopers());
278       } else {
279         System.out.println("Unknown Developers for " + plugin.getKey() + ":" + plugin.getVersion());
280       }
281     }
282     return history;
283   }
284
285   private List<ArtifactVersion> filterSnapshots(List<ArtifactVersion> versions) {
286     List<ArtifactVersion> result = new ArrayList<ArtifactVersion>();
287     for (ArtifactVersion version : versions) {
288       // Ignore snapshots
289       if (!"SNAPSHOT".equalsIgnoreCase(version.getQualifier())) {
290         result.add(version);
291       }
292     }
293     return result;
294   }
295
296   private File resolve(String groupId, String artifactId, String version) throws Exception {
297     return resolve(groupId, artifactId, version, ARTIFACT_JAR_TYPE);
298   }
299
300   private File resolve(String groupId, String artifactId, String version, String type) throws Exception {
301     Artifact artifact = artifactFactory.createArtifact(groupId, artifactId, version, Artifact.SCOPE_COMPILE, type);
302     ArtifactResolutionRequest request = new ArtifactResolutionRequest()
303         .setArtifact(artifact)
304         .setResolveTransitively(false)
305         .setLocalRepository(localRepository)
306         .setRemoteRepositories(remoteRepositories);
307     artifactResolver.resolve(request);
308     return artifact.getFile();
309   }
310
311   public static void main(String[] args) throws Exception {
312     UpdateCenter updateCenter = new UpdateCenter();
313     CmdLineParser p = new CmdLineParser(updateCenter);
314     p.parseArgument(args);
315
316     updateCenter.run();
317   }
318 }