View Javadoc
1   /*
2    * Copyright (C) 2011-2014 eXo Platform SAS.
3    *
4    * This file is part of eXo Acceptance Webapp.
5    *
6    * eXo Acceptance Webapp is free software; you can redistribute it and/or modify it
7    * under the terms of the GNU Lesser General Public License as
8    * published by the Free Software Foundation; either version 3 of
9    * the License, or (at your option) any later version.
10   *
11   * eXo Acceptance Webapp software 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 eXo Acceptance Webapp; if not, write to the Free
18   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19   * 02110-1301 USA, or see <http://www.gnu.org/licenses/>.
20   */
21  package org.exoplatform.acceptance.service.vcs;
22  
23  import org.exoplatform.acceptance.model.vcs.VCSCoordinates;
24  import org.exoplatform.acceptance.model.vcs.VCSRef;
25  import org.exoplatform.acceptance.model.vcs.VCSRepository;
26  import org.exoplatform.acceptance.service.AbstractMongoCRUDService;
27  import org.exoplatform.acceptance.service.CRUDService;
28  import org.exoplatform.acceptance.service.ConfigurationService;
29  import org.exoplatform.acceptance.storage.vcs.VCSRepositoryMongoStorage;
30  
31  import com.google.common.base.Function;
32  import com.google.common.collect.FluentIterable;
33  import java.io.File;
34  import java.util.List;
35  import javax.inject.Inject;
36  import javax.inject.Named;
37  import org.eclipse.jgit.api.Git;
38  import org.eclipse.jgit.api.errors.GitAPIException;
39  import org.eclipse.jgit.lib.Constants;
40  import org.eclipse.jgit.lib.Ref;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  import org.springframework.scheduling.annotation.Scheduled;
44  
45  /**
46   * Services to manage VCS Repositories
47   *
48   * @author Arnaud Héritier ( aheritier@exoplatform.com )
49   * @since 2.0.0
50   */
51  @Named
52  public class VCSRepositoryService extends AbstractMongoCRUDService<VCSRepository> implements CRUDService<VCSRepository> {
53  
54    /**
55     * Constant <code>LOGGER</code>
56     */
57    private static final Logger LOGGER = LoggerFactory.getLogger(VCSRepositoryService.class);
58    /**
59     * Constant <code>REF_TO_VCSREF_FUNCTION</code>
60     */
61    private static final Function<Ref, VCSRef> REF_TO_VCSREF_FUNCTION = new Function<Ref, VCSRef>() {
62      @Override
63      // TODO : Juzu throws a NPE in live mode when using @Nullable annotation
64      //@Nullable
65      //public VCSRef apply(@Nullable Ref input) {
66      public VCSRef apply(Ref input) {
67        if (null == input) {
68          return null;
69        }
70        if (input.getName().startsWith(Constants.R_HEADS)) {
71          return new VCSRef(VCSRef.Type.BRANCH, input.getName().substring(Constants.R_HEADS.length()),
72                            input.getObjectId().getName());
73        }
74        if (input.getName().startsWith(Constants.R_TAGS)) {
75          return new VCSRef(VCSRef.Type.TAG, input.getName().substring(Constants.R_TAGS.length()), input.getObjectId().getName());
76        }
77        // Git notes and remotes refs aren't supported
78        return null;
79      }
80    };
81  
82    @Inject
83    private ConfigurationService configurationService;
84    @Inject
85    private VCSRepositoryMongoStorage vcsRepositoryMongoStorage;
86  
87    /**
88     * {@inheritDoc}
89     */
90    @Override
91    protected VCSRepositoryMongoStorage getMongoStorage() {
92      return vcsRepositoryMongoStorage;
93    }
94  
95    /**
96     * Returns the directory where is stored the clone of the repository to extract data
97     *
98     * @param repository The repository object
99     * @return The directory
100    */
101   private File getCheckoutDir(VCSRepository repository) {
102     return getCheckoutDir(repository.getId());
103   }
104 
105   /**
106    * Returns the directory where is stored the clone of the repository to extract data
107    *
108    * @param repositoryId The repository identifier
109    * @return The directory
110    */
111   private File getCheckoutDir(String repositoryId) {
112     return new File(configurationService.getVCSCheckoutDirectory(), repositoryId);
113   }
114 
115   /**
116    * <p>findByName.</p>
117    *
118    * @param name a {@link java.lang.String} object.
119    * @return a {@link org.exoplatform.acceptance.model.vcs.VCSRepository} object.
120    */
121   public VCSRepository findByName(String name) {
122     return vcsRepositoryMongoStorage.findByName(name);
123   }
124 
125   // Every minute
126 
127   /**
128    * <p>updateRepositories.</p>
129    */
130   @Scheduled(fixedRate = 120000)
131   public void updateRepositories() {
132     for (VCSRepository repository : vcsRepositoryMongoStorage.findAll()) {
133       loadData(repository);
134     }
135     LOGGER.info("VCS data updated.");
136   }
137 
138   /**
139    * <p>loadData.</p>
140    *
141    * @param repository a {@link org.exoplatform.acceptance.model.vcs.VCSRepository} object.
142    */
143   private void loadData(VCSRepository repository) {
144     switch (repository.getType()) {
145       case GIT:
146         for (VCSCoordinates remote : repository.getRemoteRepositories()) {
147           try {
148             remote.setReferences(loadReferencesFromRemote(remote));
149           } catch (GitAPIException e) {
150             LOGGER.warn("Error while listing branches and tags of repository {} from its remote {} : {}",
151                         repository.getName(), remote, e.getMessage());
152           }
153         }
154         break;
155       default:
156         LOGGER.error("Unknown VCS repository type {}", repository.getType());
157         return;
158     }
159     vcsRepositoryMongoStorage.save(repository);
160   }
161 
162   /**
163    * <p>loadReferencesFromRemote.</p>
164    *
165    * @param remote a {@link org.exoplatform.acceptance.model.vcs.VCSCoordinates} object.
166    * @return a {@link java.util.List} object.
167    * @throws org.eclipse.jgit.api.errors.GitAPIException if any.
168    */
169   private List<VCSRef> loadReferencesFromRemote(VCSCoordinates remote) throws GitAPIException {
170     return FluentIterable.from(Git.lsRemoteRepository()
171                                    .setHeads(true)
172                                    .setTags(true)
173                                    .setRemote(remote.getUrl())
174                                    .call()).transform(REF_TO_VCSREF_FUNCTION).toList();
175   }
176 }