a3f3fc8e9ec85bd9f1549c30aaa29fb5a970404e
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.repository / src / main / java / org / eclipse / winery / repository / backend / filebased / GitBasedRepository.java
1 /*******************************************************************************
2  * Copyright (c) 2012-2013 University of Stuttgart.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *     Oliver Kopp - initial API and implementation
11  *******************************************************************************/
12 package org.eclipse.winery.repository.backend.filebased;
13
14 import java.io.File;
15 import java.io.FileInputStream;
16 import java.io.FileNotFoundException;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.util.Properties;
20
21 import org.eclipse.jgit.api.AddCommand;
22 import org.eclipse.jgit.api.CleanCommand;
23 import org.eclipse.jgit.api.CommitCommand;
24 import org.eclipse.jgit.api.FetchCommand;
25 import org.eclipse.jgit.api.Git;
26 import org.eclipse.jgit.api.PushCommand;
27 import org.eclipse.jgit.api.ResetCommand;
28 import org.eclipse.jgit.api.ResetCommand.ResetType;
29 import org.eclipse.jgit.api.errors.CheckoutConflictException;
30 import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
31 import org.eclipse.jgit.api.errors.GitAPIException;
32 import org.eclipse.jgit.api.errors.NoHeadException;
33 import org.eclipse.jgit.api.errors.NoMessageException;
34 import org.eclipse.jgit.api.errors.UnmergedPathsException;
35 import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
36 import org.eclipse.jgit.errors.NoWorkTreeException;
37 import org.eclipse.jgit.lib.Repository;
38 import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
39 import org.eclipse.jgit.transport.CredentialsProvider;
40 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
41 import org.eclipse.winery.repository.Prefs;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44
45 /**
46  * Used for testing only.
47  * 
48  * Allows to reset repository to a certain commit id
49  */
50 public class GitBasedRepository extends FilebasedRepository {
51         
52         private static final Logger logger = LoggerFactory.getLogger(GitBasedRepository.class);
53         
54         private final Repository gitRepo;
55         private final Git git;
56         private final CredentialsProvider cp;
57         
58         public static final String PREFERENCE_GIT_USERNAME = "git.username";
59         public static final String PREFERENCE_GIT_PASSWORD = "git.password";
60         
61         
62         /**
63          * @param repositoryLocation the location of the repository
64          * @throws IOException thrown if repository does not exist
65          */
66         public GitBasedRepository(String repositoryLocation) throws IOException {
67                 super(repositoryLocation);
68                 FileRepositoryBuilder builder = new FileRepositoryBuilder();
69                 this.gitRepo = builder.setWorkTree(this.repositoryRoot.toFile()).setMustExist(true).build();
70                 this.git = new Git(this.gitRepo);
71                 
72                 this.cp = this.initializeCredentialsProvider();
73         }
74         
75         /**
76          * Reads the properties stored in ".winery" in the repository
77          */
78         private Properties dotWineryProperties() {
79                 Properties p = new Properties();
80                 File f = new File(this.repositoryRoot.toFile(), ".winery");
81                 InputStream is;
82                 try {
83                         is = new FileInputStream(f);
84                 } catch (FileNotFoundException e1) {
85                         // .winery does not exist in the file-based repository
86                         return p;
87                 }
88                 if (is != null) {
89                         try {
90                                 p.load(is);
91                         } catch (IOException e) {
92                                 GitBasedRepository.logger.debug(e.getMessage(), e);
93                         }
94                 }
95                 return p;
96         }
97         
98         /**
99          * Uses git.username und git.password from .winery and winery.properties
100          * 
101          * Considering .winery is useful if the same war file is used on a dev
102          * server and a stable server. The WAR file cannot contain the credentials
103          * if committing is only allowed on only one of these servers
104          */
105         private CredentialsProvider initializeCredentialsProvider() {
106                 CredentialsProvider cp;
107                 
108                 Properties wp = this.dotWineryProperties();
109                 
110                 String gitUserName = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME);
111                 if (gitUserName == null) {
112                         gitUserName = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME);
113                 }
114                 
115                 String gitPassword = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD);
116                 if (gitPassword == null) {
117                         gitPassword = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD);
118                 }
119                 
120                 if (gitUserName == null) {
121                         cp = null;
122                 } else if (gitPassword == null) {
123                         cp = null;
124                 } else {
125                         cp = new UsernamePasswordCredentialsProvider(gitUserName, gitPassword);
126                 }
127                 return cp;
128         }
129         
130         public void addCommitPush() throws NoHeadException, NoMessageException, UnmergedPathsException, ConcurrentRefUpdateException, WrongRepositoryStateException, GitAPIException {
131                 AddCommand add = this.git.add();
132                 add.addFilepattern(".");
133                 add.call();
134                 
135                 CommitCommand commit = this.git.commit();
136                 commit.setMessage("Commit through Winery");
137                 commit.call();
138                 
139                 PushCommand push = this.git.push();
140                 if (this.cp != null) {
141                         push.setCredentialsProvider(this.cp);
142                 }
143                 push.call();
144         }
145         
146         private void clean() throws NoWorkTreeException, GitAPIException {
147                 GitBasedRepository.logger.trace("git clean");
148                 // remove untracked files
149                 CleanCommand clean = this.git.clean();
150                 clean.setCleanDirectories(true);
151                 clean.call();
152         }
153         
154         public void cleanAndResetHard() throws NoWorkTreeException, GitAPIException {
155                 // enable updating by resetting the content of the repository
156                 this.clean();
157                 
158                 // fetch the newest thing from upstream
159                 GitBasedRepository.logger.trace("git fetch");
160                 FetchCommand fetch = this.git.fetch();
161                 if (this.cp != null) {
162                         fetch.setCredentialsProvider(this.cp);
163                 }
164                 fetch.call();
165                 
166                 // after fetching, reset to the latest version
167                 GitBasedRepository.logger.trace("git reset --hard");
168                 ResetCommand reset = this.git.reset();
169                 reset.setMode(ResetType.HARD);
170                 reset.call();
171         }
172         
173         public void setRevisionTo(String ref) throws CheckoutConflictException, GitAPIException {
174                 this.clean();
175                 
176                 // reset repository to the desired reference
177                 ResetCommand reset = this.git.reset();
178                 reset.setMode(ResetType.HARD);
179                 reset.setRef(ref);
180                 reset.call();
181         }
182         
183         /**
184          * Returns true if authentification information (for instance, to push to
185          * upstream) is available
186          */
187         public boolean authenticationInfoAvailable() {
188                 return this.cp != null;
189         }
190 }