# HG changeset patch # User Artem Tikhomirov # Date 1360777498 -3600 # Node ID 9edfd5a223b8e8d11a22feceef86d53771714a57 # Parent dd4f6311af52496914fdef4a151fd5abc1140d8d Commit: handle empty repository case diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/core/HgCloneCommand.java --- a/src/org/tmatesoft/hg/core/HgCloneCommand.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java Wed Feb 13 18:44:58 2013 +0100 @@ -26,7 +26,6 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedList; import java.util.TreeMap; import org.tmatesoft.hg.internal.ByteArrayDataAccess; @@ -34,6 +33,8 @@ import org.tmatesoft.hg.internal.DataAccessProvider; import org.tmatesoft.hg.internal.DataSerializer; import org.tmatesoft.hg.internal.DigestHelper; +import org.tmatesoft.hg.internal.FNCacheFile; +import org.tmatesoft.hg.internal.Internals; import org.tmatesoft.hg.internal.Lifecycle; import org.tmatesoft.hg.internal.RepoInitializer; import org.tmatesoft.hg.internal.RevlogCompressor; @@ -49,6 +50,7 @@ import org.tmatesoft.hg.repo.HgRuntimeException; import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; +import org.tmatesoft.hg.util.Path; import org.tmatesoft.hg.util.PathRewrite; import org.tmatesoft.hg.util.ProgressSupport; @@ -155,7 +157,7 @@ // recently processed nodes last, so that index in the array may be used as a linkRevision or baseRevision private final ArrayList revisionSequence = new ArrayList(); - private final LinkedList fncacheFiles = new LinkedList(); + private FNCacheFile fncacheFile; private RepoInitializer repoInit; private Lifecycle.Callback lifecycleCallback; private CancelledException cancelException; @@ -176,15 +178,19 @@ public void initEmptyRepository() throws IOException { repoInit.initEmptyRepository(hgDir); + try { + assert (repoInit.getRequires() & FNCACHE) != 0; + fncacheFile = new FNCacheFile(Internals.getInstance(new HgLookup(ctx).detect(hgDir))); + } catch (HgRepositoryNotFoundException ex) { + // SHALL NOT HAPPEN provided we initialized empty repository successfully + // TODO perhaps, with WriteDownMate moving to a more appropriate location, + // we could instantiate HgRepository (or Internals) by other means, without exception? + throw new IOException("Can't access fncache for newly created repository", ex); + } } public void complete() throws IOException { - FileOutputStream fncacheFile = new FileOutputStream(new File(hgDir, "store/fncache")); - for (String s : fncacheFiles) { - fncacheFile.write(s.getBytes()); - fncacheFile.write(0x0A); // http://mercurial.selenic.com/wiki/fncacheRepoFormat - } - fncacheFile.close(); + fncacheFile.write(); } public void changelogStart() { @@ -237,8 +243,7 @@ try { revlogHeader.offset(0).baseRevision(-1); revisionSequence.clear(); - fncacheFiles.add("data/" + name + ".i"); // TODO post-1.0 this is pure guess, - // need to investigate more how filenames are kept in fncache + fncacheFile.add(Path.create(name)); File file = new File(hgDir, filename = storagePathHelper.rewrite(name).toString()); file.getParentFile().mkdirs(); indexFile = new FileOutputStream(file); diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/internal/FNCacheFile.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/FNCacheFile.java Wed Feb 13 18:44:58 2013 +0100 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2013 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.internal; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; + +import org.tmatesoft.hg.util.Path; + +/** + *
+ * The fncache file contains the paths of all filelog files in the store as encoded by mercurial.filelog.encodedir. The paths are separated by '\n' (LF). + *
+ * @see http://mercurial.selenic.com/wiki/fncacheRepoFormat + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class FNCacheFile { + + private final Internals repo; + private final ArrayList files; + + public FNCacheFile(Internals internalRepo) { + repo = internalRepo; + files = new ArrayList(); + } + + public void read(Path.Source pathFactory) throws IOException { + File f = fncacheFile(); + files.clear(); + if (!f.exists()) { + return; + } + ArrayList entries = new ArrayList(); + // names in fncache are in local encoding, shall translate to unicode + new LineReader(f, repo.getSessionContext().getLog(), repo.getFilenameEncoding()).read(new LineReader.SimpleLineCollector(), entries); + for (String e : entries) { + files.add(pathFactory.path(e)); + } + } + + public void write() throws IOException { + if (files.isEmpty()) { + return; + } + File f = fncacheFile(); + f.getParentFile().mkdirs(); + final Charset filenameEncoding = repo.getFilenameEncoding(); + FileOutputStream fncacheFile = new FileOutputStream(f); + for (Path p : files) { + String s = "data/" + p.toString() + ".i"; // TODO post-1.0 this is plain wrong. (a) likely need .d files, too; (b) what about dh/ location? + fncacheFile.write(s.getBytes(filenameEncoding)); + fncacheFile.write(0x0A); // http://mercurial.selenic.com/wiki/fncacheRepoFormat + } + fncacheFile.close(); + } + + public void add(Path p) { + files.add(p); + } + + private File fncacheFile() { + return repo.getFileFromStoreDir("fncache"); + } +} diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/internal/Internals.java --- a/src/org/tmatesoft/hg/internal/Internals.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/Internals.java Wed Feb 13 18:44:58 2013 +0100 @@ -98,7 +98,6 @@ private final boolean shallCacheRevlogsInRepo; private final DataAccessProvider dataAccess; - @SuppressWarnings("unused") private final int requiresFlags; private final PathRewrite dataPathHelper; // access to file storage area (usually under .hg/store/data/), with filenames mangled @@ -200,8 +199,11 @@ } public EncodingHelper buildFileNameEncodingHelper() { - SessionContext ctx = repo.getSessionContext(); - return new EncodingHelper(getFileEncoding(ctx), ctx); + return new EncodingHelper(getFilenameEncoding(), repo.getSessionContext()); + } + + /*package-local*/ Charset getFilenameEncoding() { + return getFileEncoding(getSessionContext()); } /*package-local*/ static Charset getFileEncoding(SessionContext ctx) { @@ -230,6 +232,9 @@ return dataPathHelper.rewrite(df.getPath().toString()); } + public int getRequiresFlags() { + return requiresFlags; + } public static boolean runningOnWindows() { return System.getProperty("os.name").indexOf("Windows") != -1; diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/internal/LineReader.java --- a/src/org/tmatesoft/hg/internal/LineReader.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/LineReader.java Wed Feb 13 18:44:58 2013 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012 TMate Software Ltd + * Copyright (c) 2012-2013 TMate Software Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +20,12 @@ import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; import java.util.Collection; import org.tmatesoft.hg.repo.HgInvalidFileException; @@ -52,13 +56,19 @@ private final File file; private final LogFacility log; + private final Charset encoding; private boolean trimLines = true; private boolean skipEmpty = true; private String ignoreThatStarts = null; public LineReader(File f, LogFacility logFacility) { + this(f, logFacility, null); + } + + public LineReader(File f, LogFacility logFacility, Charset lineEncoding) { file = f; log = logFacility; + encoding = lineEncoding; } /** @@ -92,7 +102,13 @@ BufferedReader statusFileReader = null; try { // consumer.begin(file, paramObj); - statusFileReader = new BufferedReader(new FileReader(file)); + Reader fileReader; + if (encoding == null) { + fileReader = new FileReader(file); + } else { + fileReader = new InputStreamReader(new FileInputStream(file)); + } + statusFileReader = new BufferedReader(fileReader); String line; boolean ok = true; while (ok && (line = statusFileReader.readLine()) != null) { diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/internal/RevlogStream.java --- a/src/org/tmatesoft/hg/internal/RevlogStream.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/RevlogStream.java Wed Feb 13 18:44:58 2013 +0100 @@ -224,6 +224,10 @@ return BAD_REVISION; } + /** + * @return value suitable for the corresponding field in the new revision's header, not physical offset in the file + * (which is different in case of inline revlogs) + */ public long newEntryOffset() { if (revisionCount() == 0) { return 0; @@ -324,6 +328,31 @@ } } + void revisionAdded(int revisionIndex, Nodeid revision, int baseRevisionIndex, long revisionOffset) throws HgInvalidControlFileException { + if (!outlineCached()) { + return; + } + if (baseRevisions.length != revisionIndex) { + throw new HgInvalidControlFileException(String.format("New entry's index shall be %d, not %d", baseRevisions.length, revisionIndex), null, indexFile); + } + if (baseRevisionIndex < 0 || baseRevisionIndex > baseRevisions.length) { + // baseRevisionIndex MAY be == to baseRevisions.length, it's when new revision is based on itself + throw new HgInvalidControlFileException(String.format("Base revision index %d doesn't fit [0..%d] range", baseRevisionIndex, baseRevisions.length), null, indexFile); + } + assert revision != null; + assert !revision.isNull(); + int[] baseRevisionsCopy = new int[baseRevisions.length + 1]; + System.arraycopy(baseRevisions, 0, baseRevisionsCopy, 0, baseRevisions.length); + baseRevisionsCopy[baseRevisions.length] = baseRevisionIndex; + baseRevisions = baseRevisionsCopy; + if (inline && indexRecordOffset != null) { + assert indexRecordOffset.length == revisionIndex; + int[] indexRecordOffsetCopy = new int[indexRecordOffset.length + 1]; + indexRecordOffsetCopy[indexRecordOffset.length] = offsetFieldToInlineFileOffset(revisionOffset, revisionIndex); + indexRecordOffset = indexRecordOffsetCopy; + } + } + private int getBaseRevision(int revision) { return baseRevisions[revision]; } @@ -347,9 +376,25 @@ } return revisionIndex; } + + private boolean outlineCached() { + return baseRevisions != null && baseRevisions.length > 0; + } + + // translate 6-byte offset field value to pysical file offset for inline revlogs + // DOESN'T MAKE SENSE if revlog with data is separate + private static int offsetFieldToInlineFileOffset(long offset, int recordIndex) throws HgInvalidStateException { + int o = Internals.ltoi(offset); + if (o != offset) { + // just in case, can't happen, ever, unless HG (or some other bad tool) produces index file + // with inlined data of size greater than 2 Gb. + throw new HgInvalidStateException("Data too big, offset didn't fit to sizeof(int)"); + } + return o + REVLOGV1_RECORD_SIZE * recordIndex; + } private void initOutline() throws HgInvalidControlFileException { - if (baseRevisions != null && baseRevisions.length > 0) { + if (outlineCached()) { return; } DataAccess da = getIndexStream(); @@ -357,6 +402,8 @@ if (da.isEmpty()) { // do not fail with exception if stream is empty, it's likely intentional baseRevisions = new int[0]; + // empty revlog, likely to be populated, indicate we start with a single file + inline = true; return; } int versionField = da.readInt(); @@ -385,13 +432,8 @@ // byte[] nodeid = new byte[32]; resBases.add(baseRevision); if (inline) { - int o = Internals.ltoi(offset); - if (o != offset) { - // just in case, can't happen, ever, unless HG (or some other bad tool) produces index file - // with inlined data of size greater than 2 Gb. - throw new HgInvalidStateException("Data too big, offset didn't fit to sizeof(int)"); - } - resOffsets.add(o + REVLOGV1_RECORD_SIZE * resOffsets.size()); + int o = offsetFieldToInlineFileOffset(offset, resOffsets.size()); + resOffsets.add(o); da.skip(3*4 + 32 + compressedLen); // Check: 44 (skip) + 20 (read) = 64 (total RevlogNG record size) } else { da.skip(3*4 + 32); @@ -611,4 +653,5 @@ // implementers shall not invoke DataAccess.done(), it's accomplished by #iterate at appropraite moment void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[/*20*/] nodeid, DataAccess data); } + } diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/internal/RevlogStreamWriter.java --- a/src/org/tmatesoft/hg/internal/RevlogStreamWriter.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/internal/RevlogStreamWriter.java Wed Feb 13 18:44:58 2013 +0100 @@ -94,7 +94,8 @@ revlogHeader.linkRevision(linkRevision); revlogHeader.parents(p1, p2); revlogHeader.baseRevision(writeComplete ? lastEntryIndex+1 : lastEntryBase); - revlogHeader.offset(revlogStream.newEntryOffset()); + long lastEntryOffset = revlogStream.newEntryOffset(); + revlogHeader.offset(lastEntryOffset); // revlogHeader.serialize(indexFile); @@ -114,11 +115,14 @@ dataSource.serialize(dataFile); } + lastEntryContent = content; lastEntryBase = revlogHeader.baseRevision(); lastEntryIndex++; lastEntryRevision = Nodeid.fromBinary(revisionNodeidBytes, 0); revisionCache.put(lastEntryIndex, lastEntryRevision); + + revlogStream.revisionAdded(lastEntryIndex, lastEntryRevision, lastEntryBase, lastEntryOffset); } catch (IOException ex) { String m = String.format("Failed to write revision %d", lastEntryIndex+1, null); HgInvalidControlFileException t = new HgInvalidControlFileException(m, ex, null); @@ -149,7 +153,10 @@ } private void populateLastEntry() throws HgInvalidControlFileException { - if (lastEntryIndex != NO_REVISION && lastEntryContent == null) { + if (lastEntryContent != null) { + return; + } + if (lastEntryIndex != NO_REVISION) { assert lastEntryIndex >= 0; final IOException[] failure = new IOException[1]; revlogStream.iterate(lastEntryIndex, lastEntryIndex, true, new RevlogStream.Inspector() { @@ -168,6 +175,8 @@ String m = String.format("Failed to get content of most recent revision %d", lastEntryIndex); throw revlogStream.initWithDataFile(new HgInvalidControlFileException(m, failure[0], null)); } + } else { + lastEntryContent = new byte[0]; } } @@ -267,7 +276,7 @@ // regardless whether it's inline or separate data, // offset field always represent cumulative compressedLength - // (while offset in the index file with inline==true differs by n*sizeof(header), where n is entry's position in the file) + // (while physical offset in the index file with inline==true differs by n*sizeof(header), where n is entry's position in the file) offset += compressedLength; } diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/repo/CommitFacility.java --- a/src/org/tmatesoft/hg/repo/CommitFacility.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/repo/CommitFacility.java Wed Feb 13 18:44:58 2013 +0100 @@ -18,7 +18,9 @@ import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; +import java.io.IOException; import java.nio.ByteBuffer; +import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; @@ -29,11 +31,15 @@ import org.tmatesoft.hg.internal.ByteArrayChannel; import org.tmatesoft.hg.internal.ChangelogEntryBuilder; import org.tmatesoft.hg.internal.Experimental; +import org.tmatesoft.hg.internal.FNCacheFile; import org.tmatesoft.hg.internal.ManifestEntryBuilder; import org.tmatesoft.hg.internal.ManifestRevision; +import org.tmatesoft.hg.internal.RequiresFile; +import org.tmatesoft.hg.internal.RevlogStream; import org.tmatesoft.hg.internal.RevlogStreamWriter; import org.tmatesoft.hg.util.Pair; import org.tmatesoft.hg.util.Path; +import org.tmatesoft.hg.util.LogFacility.Severity; /** * WORK IN PROGRESS @@ -81,6 +87,16 @@ if (p2Commit != NO_REVISION) { repo.getManifest().walk(p2Commit, p2Commit, c2Manifest); } + FNCacheFile fncache = null; + if ((repo.getImplHelper().getRequiresFlags() & RequiresFile.FNCACHE) != 0) { + fncache = new FNCacheFile(repo.getImplHelper()); + try { + fncache.read(new Path.SimpleSource()); + } catch (IOException ex) { + // fncache may be restored using native client, so do not treat failure to read it as severe enough to stop + repo.getSessionContext().getLog().dump(getClass(), Severity.Error, ex, "Failed to read fncache, attempt commit nevertheless"); + } + } // Pair manifestParents = getManifestParents(); Pair manifestParents = new Pair(c1Manifest.revisionIndex(), c2Manifest.revisionIndex()); TreeMap newManifestRevision = new TreeMap(); @@ -88,13 +104,21 @@ for (Path f : c1Manifest.files()) { HgDataFile df = repo.getFileNode(f); Nodeid fileKnownRev = c1Manifest.nodeid(f); - int fileRevIndex = df.getRevisionIndex(fileKnownRev); - // FIXME merged files?! - fileParents.put(f, new Pair(fileRevIndex, NO_REVISION)); + final int fileRevIndex1 = df.getRevisionIndex(fileKnownRev); + final int fileRevIndex2; + if ((fileKnownRev = c2Manifest.nodeid(f)) != null) { + // merged files + fileRevIndex2 = df.getRevisionIndex(fileKnownRev); + } else { + fileRevIndex2 = NO_REVISION; + } + + fileParents.put(f, new Pair(fileRevIndex1, fileRevIndex2)); newManifestRevision.put(f, fileKnownRev); } // // Files + ArrayList newlyAddedFiles = new ArrayList(); for (Pair e : files.values()) { HgDataFile df = e.first(); Pair fp = fileParents.get(df.getPath()); @@ -111,7 +135,14 @@ bac.write(bb); bb.clear(); } - RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo.getSessionContext(), df.content); + RevlogStream contentStream; + if (df.exists()) { + contentStream = df.content; + } else { + contentStream = repo.createStoreFile(df.getPath()); + newlyAddedFiles.add(df.getPath()); + } + RevlogStreamWriter fileWriter = new RevlogStreamWriter(repo.getSessionContext(), contentStream); Nodeid fileRev = fileWriter.addRevision(bac.toArray(), clogRevisionIndex, fp.first(), fp.second()); newManifestRevision.put(df.getPath(), fileRev); } @@ -130,6 +161,17 @@ byte[] clogContent = changelogBuilder.build(manifestRev, message); RevlogStreamWriter changelogWriter = new RevlogStreamWriter(repo.getSessionContext(), clog.content); Nodeid changesetRev = changelogWriter.addRevision(clogContent, clogRevisionIndex, p1Commit, p2Commit); + if (!newlyAddedFiles.isEmpty() && fncache != null) { + for (Path p : newlyAddedFiles) { + fncache.add(p); + } + try { + fncache.write(); + } catch (IOException ex) { + // see comment above for fnchache.read() + repo.getSessionContext().getLog().dump(getClass(), Severity.Error, ex, "Failed to write fncache, error ignored"); + } + } return changesetRev; } /* diff -r dd4f6311af52 -r 9edfd5a223b8 src/org/tmatesoft/hg/repo/HgRepository.java --- a/src/org/tmatesoft/hg/repo/HgRepository.java Tue Feb 05 22:30:21 2013 +0100 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Wed Feb 13 18:44:58 2013 +0100 @@ -184,10 +184,6 @@ public HgChangelog getChangelog() { if (changelog == null) { File chlogFile = impl.getFileFromStoreDir("00changelog.i"); - if (!chlogFile.exists()) { - // fake its existence - chlogFile = fakeNonExistentFile(chlogFile); - } RevlogStream content = new RevlogStream(impl.getDataAccess(), chlogFile); changelog = new HgChangelog(this, content); } @@ -197,9 +193,6 @@ public HgManifest getManifest() { if (manifest == null) { File manifestFile = impl.getFileFromStoreDir("00manifest.i"); - if (!manifestFile.exists()) { - manifestFile = fakeNonExistentFile(manifestFile); - } RevlogStream content = new RevlogStream(impl.getDataAccess(), manifestFile); manifest = new HgManifest(this, content, impl.buildFileNameEncodingHelper()); } @@ -512,14 +505,20 @@ return null; } - private File fakeNonExistentFile(File expected) throws HgInvalidFileException { + /*package-local*/ RevlogStream createStoreFile(Path path) throws HgInvalidControlFileException { + File f = impl.getFileFromDataDir(path); try { - File fake = File.createTempFile(expected.getName(), null); - fake.deleteOnExit(); - return fake; + if (!f.exists()) { + f.getParentFile().mkdirs(); + f.createNewFile(); + } + RevlogStream s = new RevlogStream(impl.getDataAccess(), f); + if (impl.shallCacheRevlogs()) { + streamsCache.put(path, new SoftReference(s)); + } + return s; } catch (IOException ex) { - getSessionContext().getLog().dump(getClass(), Info, ex, null); - throw new HgInvalidFileException(String.format("Failed to fake existence of file %s", expected), ex); + throw new HgInvalidControlFileException("Can't create a file in the storage", ex, f); } } diff -r dd4f6311af52 -r 9edfd5a223b8 test/org/tmatesoft/hg/test/TestCommit.java --- a/test/org/tmatesoft/hg/test/TestCommit.java Tue Feb 05 22:30:21 2013 +0100 +++ b/test/org/tmatesoft/hg/test/TestCommit.java Wed Feb 13 18:44:58 2013 +0100 @@ -16,6 +16,8 @@ */ package org.tmatesoft.hg.test; +import static org.tmatesoft.hg.repo.HgRepository.NO_REVISION; + import java.io.File; import java.io.FileWriter; import java.nio.ByteBuffer; @@ -41,15 +43,32 @@ new ExecHelper(new OutputParser.Stub(true), repoLoc).run("hg", "commit", "--addremove", "-m", "FIRST"); // HgRepository hgRepo = new HgLookup().detect(repoLoc); - CommitFacility cf = new CommitFacility(hgRepo, 0 /*NO_REVISION*/); + CommitFacility cf = new CommitFacility(hgRepo, 0); + // FIXME test diff for processing changed newlines - if a whole line or just changed endings are in the patch! + cf.add(hgRepo.getFileNode("file1"), new ByteArraySupplier("hello\nworld".getBytes())); + cf.commit("SECOND"); + // /tmp/test-commit2non-empty/.hg/ store/data/file1.i dumpData + } + + @Test + public void testCommitToEmpty() throws Exception { + File repoLoc = RepoUtils.initEmptyTempRepo("test-commit2empty"); + FileWriter fw = new FileWriter(new File(repoLoc, "file1")); + fw.write("hello"); + fw.close(); + // + HgRepository hgRepo = new HgLookup().detect(repoLoc); + CommitFacility cf = new CommitFacility(hgRepo, NO_REVISION); // FIXME test diff for processing changed newlines - if a whole line or just changed endings are in the patch! cf.add(hgRepo.getFileNode("file1"), new ByteArraySupplier("hello\nworld".getBytes())); cf.commit("commit 1"); - // /tmp/test-commit2non-empty/.hg/ store/data/file1.i dumpData } - + public static void main(String[] args) throws Exception { - new TestCommit().testCommitToNonEmpty(); + new TestCommit().testCommitToEmpty(); + if (Boolean.TRUE.booleanValue()) { + return; + } String input = "abcdefghijklmnopqrstuvwxyz"; ByteArraySupplier bas = new ByteArraySupplier(input.getBytes()); ByteBuffer bb = ByteBuffer.allocate(7);