package models; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashSet; import org.apache.commons.io.FileUtils; import org.eclipse.jgit.api.AddCommand; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.InitCommand; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.api.errors.NoFilepatternException; import org.eclipse.jgit.errors.NoWorkTreeException; import org.eclipse.jgit.errors.RevisionSyntaxException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevCommit; import utils.FileManager; public class GitHandler extends BackendHandlerInterface { static final String BASE_URL = rootBackendFolder + "git/"; public static final String REPOSITORY_URL = BASE_URL + "repo/"; static Git gitRepository = null; private GitHandler() { } /** * SingletonHolder is loaded on the first execution of * Singleton.getInstance() or the first access to SingletonHolder.INSTANCE, * not before. */ private static class SingletonHolder { private static final GitHandler INSTANCE = new GitHandler(); } public static BackendHandlerInterface getInstance() { return SingletonHolder.INSTANCE; } /** * * @deprecated This method used the command line and is deprecated, use * init() instead. */ @Deprecated public static boolean initCommandLine() { // remove the current repo System.out.println("init"); String remove = "rm -rf " + REPOSITORY_URL; System.out.println(runCommand(remove)); String mkdir = "mkdir " + REPOSITORY_URL; System.out.println(mkdir); System.out.println(runCommand(mkdir)); // init repo System.out.println(runCommand("git init " + REPOSITORY_URL)); return true; } public boolean init() { return init(REPOSITORY_URL); } public static boolean init(String repositoryURL) { if (removeExistingRepository(repositoryURL)) { try { InitCommand initCommand = new InitCommand().setBare(false) .setDirectory(new File(repositoryURL)); gitRepository = initCommand.call(); System.out.println("Success initializing the repository"); System.out.println("Repository directory: " + gitRepository.getRepository().getDirectory() .getCanonicalPath()); } catch (NullPointerException e) { System.err .println("Error creating the directory for repository:"); e.printStackTrace(); return false; } catch (GitAPIException e) { System.err.println("Error initializing the repository:"); e.printStackTrace(); return false; } catch (IOException e) { System.err .println("Error fetching the cannonical path of the repository:"); e.printStackTrace(); return false; } return true; } else { return false; } } /** * overloads removeExistingRepository(String repositoryURL) with default * repository name * * @return true if succeeded, false if not */ public boolean removeExistingRepository() { if (removeExistingRepository(REPOSITORY_URL)) return true; return false; } /** * @param repositoryURL * the repository URL * @return true if able to remove or repository inexistent; false if * existent but unable to remove. */ public static boolean removeExistingRepository(String repositoryURL) { final String gitRepositorySuffix = "/.git"; File directory = new File(repositoryURL); File gitRepository = new File(repositoryURL + gitRepositorySuffix); /** * if repository exists then remove it */ if (gitRepository.exists()) { try { FileUtils.deleteDirectory(gitRepository); FileUtils.cleanDirectory(directory); } catch (IOException e) { System.out.println("Failed to remove the repository: " + repositoryURL); e.printStackTrace(); return false; } return true; } else { /** * else its not required to */ return true; } } /** * Overloads the add(Repository repo, String filepattern, boolean update) * method passing the update value as false and using the current git * repository * * @param repo * @param filepattern * @return */ public static boolean add(String filepattern) { if (GitHandler.gitRepository == null) { System.err.println("Have not init repo: " + filepattern); return false; } if (add(GitHandler.gitRepository.getRepository(), filepattern, false)) return true; return false; } /** * Overloads the add(Repository repo, String filepattern, boolean update) * method passing the update value as false * * @param repo * @param filepattern * @return */ public static boolean add(Repository repo, String filepattern) { if (add(repo, filepattern, false)) return true; return false; } public Logs getLog() { String returnString = ""; Logs logs = new Logs(); try { for (RevCommit element : gitRepository.log().call()) { logs.addLog(new Log(element.getName(), element.getFullMessage())); } } catch (GitAPIException e) { // TODO Auto-generated catch block e.printStackTrace(); } return logs; } /** * Adds a file/dir to the repository for commit * * @param repo * @param filepattern * @param update * @return */ public static boolean add(Repository repo, String filepattern, boolean update) { try { AddCommand addCommand = new AddCommand(repo); addCommand.addFilepattern(filepattern); addCommand.setUpdate(update); try { addCommand.call(); } catch (NoFilepatternException e) { System.err .println("Failed to add file, did not include a file pattern? File pattern received was: " + filepattern); // e.printStackTrace(); return false; } catch (GitAPIException e) { System.err.println("Fail to add the file to the repository:"); // e.printStackTrace(); return false; } } catch (JGitInternalException e) { System.err .println("Fail to add the file to the repository internal error"); // e.printStackTrace(); return false; } return true; } public Object getRepository() { return gitRepository; } /** * * @return The working directory path * @throws IOException */ public String getRepositoryPath() { return GitHandler.gitRepository.getRepository().getWorkTree().getPath(); } public ArrayList<RepositoryFile> getWorkingDirFiles() { // TODO: check if working dir is up to date ArrayList<RepositoryFile> workingDirFiles = null; File workingDir; try { workingDir = GitHandler.gitRepository.getRepository().getWorkTree(); workingDirFiles = getWorkingDirFilesPath(workingDir); } catch (NoWorkTreeException e) { // TODO Auto-generated catch block e.printStackTrace(); } return workingDirFiles; } // TODO: use commons.io.FileUtils to fetch those private static ArrayList<RepositoryFile> getWorkingDirFilesPath( File workingDir) { ArrayList<RepositoryFile> workingDirFiles = new ArrayList<RepositoryFile>(); for (final File fileEntry : workingDir.listFiles()) { if (fileEntry.isDirectory()) { // TODO: go recursive } else { workingDirFiles.add(new RepositoryFile(fileEntry.getPath())); } } return workingDirFiles; } @Override public String commitAFile(TempFile tf) { // TODO Auto-generated method stub throw new UnsupportedOperationException(); } @Override public TempFile getFile(String url) { // TODO Auto-generated method stub throw new UnsupportedOperationException(); } /** * Only prepared for a single file TODO: Needs to be able to receive more * than one */ @Override public boolean commit(String url, String content, String message, User user) { buildFile(url, content); /** * Add to repository */ if(!GitHandler.add(url)){ System.out.println("Fail to add the file to the repository"); } System.out.println("success adding file"); /** * Commit changes */ RevCommit commit; boolean committed = false; try { commit = GitHandler.gitRepository.commit() .setAuthor(user.getName(), user.getEmail()) .setMessage(message).call(); /** * Is this really still necessary? */ int commitTime = Integer.MIN_VALUE; while (commitTime == Integer.MIN_VALUE) { /** * wait for the commit to be successful */ Thread.sleep(100); commitTime = commit.getCommitTime(); } committed = true; } catch (GitAPIException e1) { // TODO Auto-generated catch block e1.printStackTrace(); return committed; } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); return committed; } return committed; } /** * Creates a File on the repository directory * * @param url * @param content */ // TODO: Should be moved away from here private static void buildFile(String url, String content) { String fileName = url; String fileContent = content; String filePath = GitHandler.REPOSITORY_URL; try { File file=FileManager.createFile(fileContent, fileName, filePath); Runtime rt = Runtime.getRuntime(); System.out.println("running xmllint"); Process pr = rt.exec("/usr/bin/xmllint --c14n "+filePath+fileName); System.out.println("create file "+filePath+fileName+".norm"); // hook up child process output to parent InputStream lsOut = pr.getInputStream(); InputStreamReader r = new InputStreamReader(lsOut); BufferedReader in = new BufferedReader(r); // read the child process' output fileContent=""; char c; int i; boolean questionMark=false; boolean inside=false; while ((i = lsOut.read()) != -1) { c=(char)i; if(c=='<'){ inside=true; } if(c=='>'){ if(!questionMark){ fileContent+='\n'; } inside=false; } if(inside&&c==' '){ fileContent+='\n'; }else{ fileContent+=c; } if(c=='?'){ questionMark=true; }else{ questionMark=false; } } FileUtils.write(file, fileContent); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public RepositoryRevision getRepositoryHEAD() { RepositoryRevision head = new RepositoryRevision(); populateHEADRepositoryFiles(head); Git git = (Git) this.getRepository(); Repository repository = git.getRepository(); populateHEADGeneralData(head,git); return head; } private void populateHEADGeneralData(RepositoryRevision head,Git git) { try { ObjectId headObject = git.getRepository().resolve(Constants.HEAD); head.setLastCommit(git.log().add(headObject).call().iterator() .next().getId().getName()); head.setLastCommitMessage(git.log().add(headObject).call() .iterator().next().getShortMessage()); head.setLastCommitAuthor(git.log().add(headObject).call() .iterator().next().getAuthorIdent().getName()); } catch (RevisionSyntaxException | IOException | GitAPIException | NullPointerException e) { // TODO Auto-generated catch block e.printStackTrace(); } } private void populateHEADRepositoryFiles(RepositoryRevision head) { head.setRepositoryFiles(this.getWorkingDirFiles()); for (RepositoryFile repoFile : head.getRepositoryFiles()) { repoFile.setFileContent(FileManager.readFileToString(repoFile .getFileURL())); repoFile.setFileURL(this.getStrippedFileURL(repoFile.getFileURL())); } } @Override public RepositoryRevision checkout(String revision) { System.out.println("running checkout"); Git git = (Git) this.getRepository(); Repository repository = git.getRepository(); try { git.checkout().setStartPoint(revision).setCreateBranch(true).setName("newbranch").call(); }catch (GitAPIException e) { // TODO Auto-generated catch block e.printStackTrace(); } RepositoryRevision head = new RepositoryRevision(); populateHEADRepositoryFiles(head); populateHEADGeneralData(head,git); try { git.checkout().setName("master").call(); } catch (GitAPIException e) { // TODO Auto-generated catch block e.printStackTrace(); } return head; } @Override public HashSet<String> getDiff(int relativeRevisionId) { // TODO Auto-generated method stub return null; } @Override public int getVersionId() { // TODO Auto-generated method stub return 0; } @Override public boolean revert(int relativeRevision) { // TODO Auto-generated method stub return false; } @Override public boolean commit(String url, String content, String message, User user, int relativeVersion) { // TODO Auto-generated method stub return false; } @Override public long getSize() { return folderSize(new File(REPOSITORY_URL)); } }