/** * Get a map from author names to their ids in the database. The authors that are not in the * database are added to it. * * @param conn the connection to the database * @param history the history to get the author names from * @param reposId the id of the repository * @return a map from author names to author ids */ private Map<String, Integer> getAuthors(ConnectionResource conn, History history, int reposId) throws SQLException { HashMap<String, Integer> map = new HashMap<String, Integer>(); PreparedStatement ps = conn.getStatement(GET_AUTHORS); ps.setInt(1, reposId); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { map.put(rs.getString(1), rs.getInt(2)); } } PreparedStatement insert = conn.getStatement(ADD_AUTHOR); insert.setInt(1, reposId); for (HistoryEntry entry : history.getHistoryEntries()) { String author = entry.getAuthor(); if (!map.containsKey(author)) { int id = nextAuthorId.getAndIncrement(); insert.setString(2, author); insert.setInt(3, id); insert.executeUpdate(); map.put(author, id); conn.commit(); } } return map; }
/** Test of parse method, of class ClearCaseHistoryParser. */ @Test public void parseFileHistory() throws Exception { String author1 = "First Last (username)"; String author2 = "First2 Last2 (username2)"; String output = "create version\n" + "20020618.212343\n" + author1 + "\n" + "/main/3\n" + "Merge from eeeee for ffffff\n" + ".\n" + "create version\n" + "20020222.164239\n" + author2 + "\n" + "/main/2\n" + "Merge from projper branch.\n" + "Adding aaaaaaa to the yyyyy.\n" + ".\n" + "create version\n" + "20020208.150825\n" + author2 + "\n" + "/main/1\n" + "Target for javac set to 1.3.\n" + "Fixed handling of " + " res directory.\n" + ".\n" + "create version\n" + "20010924.095104\n" + author2 + "\n" + "/main/0\n" + "\n" + ".\n" + "create branch\n" + "20010924.095104\n" + author2 + "\n" + "/main\n" + "\n" + ".\n" + "create file element\n" + "20010924.095104\n" + author1 + "\n" + "\n" + "\n" + "."; History result = instance.parse(output); assertNotNull(result); assertEquals(4, result.getHistoryEntries().size()); HistoryEntry e1 = result.getHistoryEntries().get(0); assertEquals("/main/3", e1.getRevision()); assertEquals(author1, e1.getAuthor()); assertEquals(0, e1.getFiles().size()); assertTrue(e1.getMessage().contains("eeeee")); HistoryEntry e4 = result.getHistoryEntries().get(3); assertEquals("/main/0", e4.getRevision()); assertEquals(author2, e4.getAuthor()); assertEquals(0, e4.getFiles().size()); }
private void storeHistory(ConnectionResource conn, History history, Repository repository) throws SQLException { Integer reposId = null; Map<String, Integer> authors = null; Map<String, Integer> files = null; Map<String, Integer> directories = null; PreparedStatement addChangeset = null; PreparedStatement addDirchange = null; PreparedStatement addFilechange = null; PreparedStatement addFilemove = null; RuntimeEnvironment env = RuntimeEnvironment.getInstance(); // return immediately when there is nothing to do List<HistoryEntry> entries = history.getHistoryEntries(); if (entries.isEmpty()) { return; } for (int i = 0; ; i++) { try { if (reposId == null) { reposId = getRepositoryId(conn, repository); conn.commit(); } if (authors == null) { authors = getAuthors(conn, history, reposId); conn.commit(); } if (directories == null || files == null) { Map<String, Integer> dirs = new HashMap<String, Integer>(); Map<String, Integer> fls = new HashMap<String, Integer>(); getFilesAndDirectories(conn, history, reposId, dirs, fls); conn.commit(); directories = dirs; files = fls; } if (addChangeset == null) { addChangeset = conn.getStatement(ADD_CHANGESET); } if (addDirchange == null) { addDirchange = conn.getStatement(ADD_DIRCHANGE); } if (addFilechange == null) { addFilechange = conn.getStatement(ADD_FILECHANGE); } if (addFilemove == null) { addFilemove = conn.getStatement(ADD_FILEMOVE); } // Success! Break out of the loop. break; } catch (SQLException sqle) { handleSQLException(sqle, i); conn.rollback(); } } addChangeset.setInt(1, reposId); // getHistoryEntries() returns the entries in reverse chronological // order, but we want to insert them in chronological order so that // their auto-generated identity column can be used as a chronological // ordering column. Otherwise, incremental updates will make the // identity column unusable for chronological ordering. So therefore // we walk the list backwards. for (ListIterator<HistoryEntry> it = entries.listIterator(entries.size()); it.hasPrevious(); ) { HistoryEntry entry = it.previous(); retry: for (int i = 0; ; i++) { try { addChangeset.setString(2, entry.getRevision()); addChangeset.setInt(3, authors.get(entry.getAuthor())); addChangeset.setTimestamp(4, new Timestamp(entry.getDate().getTime())); String msg = entry.getMessage(); // Truncate the message if it can't fit in a VARCHAR // (bug #11663). if (msg.length() > MAX_MESSAGE_LENGTH) { msg = truncate(msg, MAX_MESSAGE_LENGTH); } addChangeset.setString(5, msg); int changesetId = nextChangesetId.getAndIncrement(); addChangeset.setInt(6, changesetId); addChangeset.executeUpdate(); // Add one row for each file in FILECHANGES, and one row // for each path element of the directories in DIRCHANGES. Set<String> addedDirs = new HashSet<String>(); addDirchange.setInt(1, changesetId); addFilechange.setInt(1, changesetId); for (String file : entry.getFiles()) { // ignore ignored files String repodir = ""; try { repodir = env.getPathRelativeToSourceRoot(new File(repository.getDirectoryName()), 0); } catch (IOException ex) { Logger.getLogger(JDBCHistoryCache.class.getName()).log(Level.SEVERE, null, ex); } String fullPath = toUnixPath(file); if (!history.isIgnored(file.substring(repodir.length() + 1))) { int fileId = files.get(fullPath); addFilechange.setInt(2, fileId); addFilechange.executeUpdate(); } String[] pathElts = splitPath(fullPath); for (int j = 0; j < pathElts.length; j++) { String dir = unsplitPath(pathElts, j); // Only add to DIRCHANGES if we haven't already // added this dir/changeset combination. if (!addedDirs.contains(dir)) { addDirchange.setInt(2, directories.get(dir)); addDirchange.executeUpdate(); addedDirs.add(dir); } } } conn.commit(); // Successfully added the entry. Break out of retry loop. break retry; } catch (SQLException sqle) { handleSQLException(sqle, i); conn.rollback(); } } } /* * Special handling for certain files - this is mainly for files which * have been renamed in Mercurial repository. * This ensures that their complete history (follow) will be saved. */ for (String filename : history.getIgnoredFiles()) { String file_path = repository.getDirectoryName() + File.separatorChar + filename; File file = new File(file_path); String repo_path = file_path.substring(env.getSourceRootPath().length()); History hist; try { hist = repository.getHistory(file); } catch (HistoryException ex) { Logger.getLogger(JDBCHistoryCache.class.getName()).log(Level.SEVERE, null, ex); continue; } int fileId = files.get(repo_path); for (HistoryEntry entry : hist.getHistoryEntries()) { retry: for (int i = 0; ; i++) { try { int changesetId = getIdForRevision(entry.getRevision()); /* * If the file exists in the changeset, store it in * the table tracking moves of the file when it had * one of its precedent names so it can be found * when performing historyget on directory. */ if (entry.getFiles().contains(repo_path)) { addFilechange.setInt(1, changesetId); addFilechange.setInt(2, fileId); addFilechange.executeUpdate(); } else { addFilemove.setInt(1, changesetId); addFilemove.setInt(2, fileId); addFilemove.executeUpdate(); } conn.commit(); break retry; } catch (SQLException sqle) { handleSQLException(sqle, i); conn.rollback(); } } } } }
/** Test of parse method, of class ClearCaseHistoryParser. */ @Test public void parseDirHistory() throws Exception { String author1 = "First Last (username)"; String author2 = "First2 Last2 (username2)"; String output = "create directory version\n" + "20050401.162902\n" + author1 + "\n" + "/main/3\n" + "Removed directory element \"prototype\".\n" + ".\n" + "create directory version\n" + "20020618.215917\n" + author2 + "\n" + "/main/2\n" + "Merge from wwwww for dddddd\n" + ".\n" + "create directory version\n" + "20010228.174617\n" + author1 + "\n" + "/main/1\n" + "New structure.\n" + "\n" + "Added directory element \"generic\".\n" + "Added directory element \"prototype\".\n" + "Added directory element \"install\".\n" + "Added directory element \"service\".\n" + ".\n" + "create directory version\n" + "20001215.092522\n" + author2 + "\n" + "/main/0\n" + "\n" + ".\n" + "create branch\n" + "20001215.092522\n" + author1 + "\n" + "/main\n" + "\n" + ".\n" + "create directory element\n" + "20001215.092522\n" + author1 + "\n" + "\n" + "\n" + "."; History result = instance.parse(output); assertNotNull(result); assertEquals(4, result.getHistoryEntries().size()); HistoryEntry e1 = result.getHistoryEntries().get(0); assertEquals("/main/3", e1.getRevision()); assertEquals(author1, e1.getAuthor()); assertEquals(0, e1.getFiles().size()); assertTrue(e1.getMessage().contains("prototype")); HistoryEntry e4 = result.getHistoryEntries().get(3); assertEquals("/main/0", e4.getRevision()); assertEquals(author2, e4.getAuthor()); assertEquals(0, e4.getFiles().size()); }