/******************************************************************************* * Copyright (c) 2012-2017 Codenvy, S.A. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.git; import org.eclipse.che.api.project.shared.Constants; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import javax.annotation.PostConstruct; import javax.inject.Singleton; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Checks Git configuration to ensure properly work Git-extension in Codenvy. * * Here we check that we have correct setting for git ignore. * Must be ignored files : * .che/misc.xml * .vfs/ * like system files for Codenvy * * @author Artem Zatsarynnyi */ @Singleton public class GitConfigurationChecker { private static final Logger LOG = LoggerFactory.getLogger(GitConfigurationChecker.class); /** Special comment for global .gitignore file. Define begin of Codenvy-specific patterns. */ private static final String CODENVY_COMMENT = "# Codenvy files"; /** Codenvy-specific file patterns to ignore by Git. */ private static final Set<String> GITIGNORE_PATTERNS = new LinkedHashSet<>(); /** Path to the global gitconfig file. */ private final Path GLOBAL_GITCONFIG_FILE_PATH; /** Path to the file that contains Codenvy-specific file patterns to ignore its by Git. */ private final Path DEFAULT_GITIGNORE_FILE_PATH; public GitConfigurationChecker() { GLOBAL_GITCONFIG_FILE_PATH = Paths.get(System.getProperty("user.home") + "/.gitconfig"); DEFAULT_GITIGNORE_FILE_PATH = Paths.get(System.getProperty("user.home") + "/.gitignore_codenvy"); GITIGNORE_PATTERNS.add(Constants.CHE_DIR + "/"); GITIGNORE_PATTERNS.add(".che/"); GITIGNORE_PATTERNS.add(".vfs/"); } // Constructor for unit-tests. GitConfigurationChecker(Path globalGitconfigFilePath, Path gitIgnoreFilePath) { GLOBAL_GITCONFIG_FILE_PATH = globalGitconfigFilePath; DEFAULT_GITIGNORE_FILE_PATH = gitIgnoreFilePath; GITIGNORE_PATTERNS.add(Constants.CHE_DIR + "/"); GITIGNORE_PATTERNS.add(".che/"); GITIGNORE_PATTERNS.add(".vfs/"); } @PostConstruct public void start() { try { ensureExistingGlobalGitconfigFile(); checkExcludesfileProperty(); } catch (IOException e) { LOG.error(e.getMessage(), e); } } private void ensureExistingGlobalGitconfigFile() throws IOException { if (Files.notExists(GLOBAL_GITCONFIG_FILE_PATH)) { Files.createFile(GLOBAL_GITCONFIG_FILE_PATH); } } private void checkExcludesfileProperty() throws IOException { List<String> gitconfigContent = Files.readAllLines(GLOBAL_GITCONFIG_FILE_PATH, Charset.forName("UTF-8")); for (String s : gitconfigContent) { if (s.trim().startsWith("excludesfile")) { final String line = s.trim(); Path existingGitignoreFilePath = Paths.get(line.substring(line.indexOf("=") + 2)); writeCodenvyExcludesToFile(existingGitignoreFilePath); return; } } writeCodenvyExcludesToFile(DEFAULT_GITIGNORE_FILE_PATH); Files.write(GLOBAL_GITCONFIG_FILE_PATH, getExcludesfilePropertyDefaultContent().getBytes(), StandardOpenOption.APPEND); } private void writeCodenvyExcludesToFile(Path path) throws IOException { List<String> toAdd = new ArrayList<>(GITIGNORE_PATTERNS); if (Files.exists(path)) { List<String> existingRules = Files.readAllLines(path, Charset.forName("UTF-8")); // add only new rules to the existing .gitignore file for (String rule : existingRules) { toAdd.remove(rule.trim()); } } if (!toAdd.isEmpty()) { toAdd.add(0, '\n' + CODENVY_COMMENT); Files.write(path, toAdd, Charset.forName("UTF-8"), StandardOpenOption.CREATE, StandardOpenOption.APPEND); } } private String getExcludesfilePropertyDefaultContent() { return "\n" + "[core]\n" + "\texcludesfile = " + DEFAULT_GITIGNORE_FILE_PATH.toString().replace("\\", "/") + "\n"; } }