aboutsummaryrefslogtreecommitdiffstats
path: root/winery/org.eclipse.winery.repository/src/main/java/org/eclipse/winery/repository/backend/filebased/GitBasedRepository.java
blob: a3f3fc8e9ec85bd9f1549c30aaa29fb5a970404e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*******************************************************************************
 * Copyright (c) 2012-2013 University of Stuttgart.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * and the Apache License 2.0 which both accompany this distribution,
 * and are available at http://www.eclipse.org/legal/epl-v10.html
 * and http://www.apache.org/licenses/LICENSE-2.0
 *
 * Contributors:
 *     Oliver Kopp - initial API and implementation
 *******************************************************************************/
package org.eclipse.winery.repository.backend.filebased;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import org.eclipse.jgit.api.AddCommand;
import org.eclipse.jgit.api.CleanCommand;
import org.eclipse.jgit.api.CommitCommand;
import org.eclipse.jgit.api.FetchCommand;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PushCommand;
import org.eclipse.jgit.api.ResetCommand;
import org.eclipse.jgit.api.ResetCommand.ResetType;
import org.eclipse.jgit.api.errors.CheckoutConflictException;
import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.api.errors.NoMessageException;
import org.eclipse.jgit.api.errors.UnmergedPathsException;
import org.eclipse.jgit.api.errors.WrongRepositoryStateException;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.storage.file.FileRepositoryBuilder;
import org.eclipse.jgit.transport.CredentialsProvider;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.eclipse.winery.repository.Prefs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Used for testing only.
 * 
 * Allows to reset repository to a certain commit id
 */
public class GitBasedRepository extends FilebasedRepository {
	
	private static final Logger logger = LoggerFactory.getLogger(GitBasedRepository.class);
	
	private final Repository gitRepo;
	private final Git git;
	private final CredentialsProvider cp;
	
	public static final String PREFERENCE_GIT_USERNAME = "git.username";
	public static final String PREFERENCE_GIT_PASSWORD = "git.password";
	
	
	/**
	 * @param repositoryLocation the location of the repository
	 * @throws IOException thrown if repository does not exist
	 */
	public GitBasedRepository(String repositoryLocation) throws IOException {
		super(repositoryLocation);
		FileRepositoryBuilder builder = new FileRepositoryBuilder();
		this.gitRepo = builder.setWorkTree(this.repositoryRoot.toFile()).setMustExist(true).build();
		this.git = new Git(this.gitRepo);
		
		this.cp = this.initializeCredentialsProvider();
	}
	
	/**
	 * Reads the properties stored in ".winery" in the repository
	 */
	private Properties dotWineryProperties() {
		Properties p = new Properties();
		File f = new File(this.repositoryRoot.toFile(), ".winery");
		InputStream is;
		try {
			is = new FileInputStream(f);
		} catch (FileNotFoundException e1) {
			// .winery does not exist in the file-based repository
			return p;
		}
		if (is != null) {
			try {
				p.load(is);
			} catch (IOException e) {
				GitBasedRepository.logger.debug(e.getMessage(), e);
			}
		}
		return p;
	}
	
	/**
	 * Uses git.username und git.password from .winery and winery.properties
	 * 
	 * Considering .winery is useful if the same war file is used on a dev
	 * server and a stable server. The WAR file cannot contain the credentials
	 * if committing is only allowed on only one of these servers
	 */
	private CredentialsProvider initializeCredentialsProvider() {
		CredentialsProvider cp;
		
		Properties wp = this.dotWineryProperties();
		
		String gitUserName = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME);
		if (gitUserName == null) {
			gitUserName = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_USERNAME);
		}
		
		String gitPassword = wp.getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD);
		if (gitPassword == null) {
			gitPassword = Prefs.INSTANCE.getProperties().getProperty(GitBasedRepository.PREFERENCE_GIT_PASSWORD);
		}
		
		if (gitUserName == null) {
			cp = null;
		} else if (gitPassword == null) {
			cp = null;
		} else {
			cp = new UsernamePasswordCredentialsProvider(gitUserName, gitPassword);
		}
		return cp;
	}
	
	public void addCommitPush() throws NoHeadException, NoMessageException, UnmergedPathsException, ConcurrentRefUpdateException, WrongRepositoryStateException, GitAPIException {
		AddCommand add = this.git.add();
		add.addFilepattern(".");
		add.call();
		
		CommitCommand commit = this.git.commit();
		commit.setMessage("Commit through Winery");
		commit.call();
		
		PushCommand push = this.git.push();
		if (this.cp != null) {
			push.setCredentialsProvider(this.cp);
		}
		push.call();
	}
	
	private void clean() throws NoWorkTreeException, GitAPIException {
		GitBasedRepository.logger.trace("git clean");
		// remove untracked files
		CleanCommand clean = this.git.clean();
		clean.setCleanDirectories(true);
		clean.call();
	}
	
	public void cleanAndResetHard() throws NoWorkTreeException, GitAPIException {
		// enable updating by resetting the content of the repository
		this.clean();
		
		// fetch the newest thing from upstream
		GitBasedRepository.logger.trace("git fetch");
		FetchCommand fetch = this.git.fetch();
		if (this.cp != null) {
			fetch.setCredentialsProvider(this.cp);
		}
		fetch.call();
		
		// after fetching, reset to the latest version
		GitBasedRepository.logger.trace("git reset --hard");
		ResetCommand reset = this.git.reset();
		reset.setMode(ResetType.HARD);
		reset.call();
	}
	
	public void setRevisionTo(String ref) throws CheckoutConflictException, GitAPIException {
		this.clean();
		
		// reset repository to the desired reference
		ResetCommand reset = this.git.reset();
		reset.setMode(ResetType.HARD);
		reset.setRef(ref);
		reset.call();
	}
	
	/**
	 * Returns true if authentification information (for instance, to push to
	 * upstream) is available
	 */
	public boolean authenticationInfoAvailable() {
		return this.cp != null;
	}
}