# HG changeset patch # User Artem Tikhomirov # Date 1316144132 -7200 # Node ID 981f9f50bb6c70a0d6ae3a30f91f2876c05a4b65 # Parent 32890bab7209c2bbae255e81d6da7f6e16202b05 Issue 11: Error log facility. SessionContext to share common facilities diff -r 32890bab7209 -r 981f9f50bb6c cmdline/org/tmatesoft/hg/console/Main.java --- a/cmdline/org/tmatesoft/hg/console/Main.java Wed Sep 14 04:41:57 2011 +0200 +++ b/cmdline/org/tmatesoft/hg/console/Main.java Fri Sep 16 05:35:32 2011 +0200 @@ -26,35 +26,37 @@ import org.junit.Assert; import org.tmatesoft.hg.core.HgBadStateException; +import org.tmatesoft.hg.core.HgCatCommand; import org.tmatesoft.hg.core.HgDataStreamException; -import org.tmatesoft.hg.core.HgLogCommand; -import org.tmatesoft.hg.core.HgCatCommand; import org.tmatesoft.hg.core.HgFileInformer; import org.tmatesoft.hg.core.HgFileRevision; +import org.tmatesoft.hg.core.HgLogCommand; import org.tmatesoft.hg.core.HgManifestCommand; import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.internal.ByteArrayChannel; import org.tmatesoft.hg.internal.DigestHelper; import org.tmatesoft.hg.internal.PathGlobMatcher; import org.tmatesoft.hg.internal.RelativePathRewrite; +import org.tmatesoft.hg.internal.StreamLogFacility; import org.tmatesoft.hg.repo.HgBranches; import org.tmatesoft.hg.repo.HgChangelog; +import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; import org.tmatesoft.hg.repo.HgDataFile; import org.tmatesoft.hg.repo.HgDirstate; +import org.tmatesoft.hg.repo.HgDirstate.EntryKind; +import org.tmatesoft.hg.repo.HgDirstate.Record; import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgManifest; +import org.tmatesoft.hg.repo.HgManifest.Flags; import org.tmatesoft.hg.repo.HgMergeState; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.repo.HgStatusCollector; import org.tmatesoft.hg.repo.HgStatusInspector; import org.tmatesoft.hg.repo.HgSubrepoLocation; -import org.tmatesoft.hg.repo.HgManifest.Flags; import org.tmatesoft.hg.repo.HgSubrepoLocation.Kind; import org.tmatesoft.hg.repo.HgWorkingCopyStatusCollector; -import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; -import org.tmatesoft.hg.repo.HgDirstate.EntryKind; -import org.tmatesoft.hg.repo.HgDirstate.Record; import org.tmatesoft.hg.util.FileWalker; +import org.tmatesoft.hg.util.LogFacility; import org.tmatesoft.hg.util.Pair; import org.tmatesoft.hg.util.Path; import org.tmatesoft.hg.util.PathRewrite; @@ -65,6 +67,7 @@ * @author Artem Tikhomirov * @author TMate Software Ltd. */ +@SuppressWarnings("unused") public class Main { private Options cmdLineOpts; @@ -82,6 +85,7 @@ public static void main(String[] args) throws Exception { Main m = new Main(args); + m.testConsoleLog(); // m.testTreeTraversal(); // m.testRevisionMap(); // m.testSubrepos(); @@ -94,7 +98,7 @@ // m.dumpBranches(); // m.inflaterLengthException(); // m.dumpIgnored(); - m.dumpDirstate(); +// m.dumpDirstate(); // m.testStatusInternals(); // m.catCompleteHistory(); // m.dumpCompleteManifestLow(); @@ -102,6 +106,20 @@ // m.bunchOfTests(); } + private void testConsoleLog() { + LogFacility fc = new StreamLogFacility(true, true, true, System.out); + System.out.printf("isDebug: %s, isInfo:%s\n", fc.isDebug(), fc.isInfo()); + fc.debug(getClass(), "%d", 1); + fc.info(getClass(), "%d\n", 2); + fc.warn(getClass(), "%d\n", 3); + fc.error(getClass(), "%d", 4); + Exception ex = new Exception(); + fc.debug(getClass(), ex, "message"); + fc.info(getClass(), ex, null); + fc.warn(getClass(), ex, null); + fc.error(getClass(), ex, "message"); + } + private void testTreeTraversal() throws Exception { File repoRoot = hgRepo.getWorkingDir(); Path.Source pathSrc = new Path.SimpleSource(new PathRewrite.Composite(new RelativePathRewrite(repoRoot), hgRepo.getToRepoPathHelper())); diff -r 32890bab7209 -r 981f9f50bb6c cmdline/org/tmatesoft/hg/console/Remote.java --- a/cmdline/org/tmatesoft/hg/console/Remote.java Wed Sep 14 04:41:57 2011 +0200 +++ b/cmdline/org/tmatesoft/hg/console/Remote.java Fri Sep 16 05:35:32 2011 +0200 @@ -36,7 +36,6 @@ import javax.net.ssl.X509TrustManager; import org.tmatesoft.hg.internal.ConfigFile; -import org.tmatesoft.hg.internal.Internals; /** * WORK IN PROGRESS, DO NOT USE @@ -91,7 +90,7 @@ empty result */ public static void main(String[] args) throws Exception { - ConfigFile cfg = new Internals().newConfigFile(); + ConfigFile cfg = new ConfigFile(); cfg.addLocation(new File(System.getProperty("user.home"), ".hgrc")); String svnkitServer = cfg.getSection("paths").get("svnkit"); // URL url = new URL(svnkitServer + "?cmd=branches&nodes=30bd389788464287cee22ccff54c330a4b715de5"); diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgBadArgumentException.java --- a/src/org/tmatesoft/hg/core/HgBadArgumentException.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgBadArgumentException.java Fri Sep 16 05:35:32 2011 +0200 @@ -17,7 +17,14 @@ package org.tmatesoft.hg.core; /** - * + * Thrown when client supplied an argument that turned out to be incorrect. + * E.g. an {@link java.net.URL URL} of remote server or {@link java.io.File File} destination for a new repository + * might be otherwise valid, but unsuitable for the purpose of the operation. + * + * Not a replacement for {@link IllegalArgumentException} or {@link NullPointerException}. + * + * TODO review usage to match description + * * @author Artem Tikhomirov * @author TMate Software Ltd. */ diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgCloneCommand.java --- a/src/org/tmatesoft/hg/core/HgCloneCommand.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java Fri Sep 16 05:35:32 2011 +0200 @@ -71,9 +71,9 @@ return this; } - public HgRepository execute() throws HgException, CancelledException { + public HgRepository execute() throws HgBadArgumentException, HgRemoteConnectionException, HgInvalidFileException, CancelledException { if (destination == null) { - throw new HgBadArgumentException("Destination not set", null); + throw new IllegalArgumentException("Destination not set", null); } if (srcRepo == null || srcRepo.isInvalid()) { throw new HgBadArgumentException("Bad source repository", null); @@ -101,7 +101,7 @@ completeChanges.inspectAll(mate); mate.complete(); } catch (IOException ex) { - throw new HgException(ex); + throw new HgInvalidFileException(getClass().getName(), ex); } finally { completeChanges.unlink(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgFileInformer.java --- a/src/org/tmatesoft/hg/core/HgFileInformer.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgFileInformer.java Fri Sep 16 05:35:32 2011 +0200 @@ -18,6 +18,7 @@ import org.tmatesoft.hg.internal.ManifestRevision; import org.tmatesoft.hg.repo.HgDataFile; +import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.util.Path; @@ -114,7 +115,7 @@ } } } catch (HgDataStreamException ex) { - ex.printStackTrace(); // XXX log(INFO) + HgInternals.getContext(repo).getLog().warn(getClass(), ex, "Follow copy/rename failed"); // ignore now, however if there's IStatus retval, might report error with reasonable explanation. // Perhaps, may add a String reason() method with such info? } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgIncomingCommand.java --- a/src/org/tmatesoft/hg/core/HgIncomingCommand.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgIncomingCommand.java Fri Sep 16 05:35:32 2011 +0200 @@ -16,7 +16,6 @@ */ package org.tmatesoft.hg.core; -import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; @@ -100,10 +99,10 @@ * Reported changes are from any branch (limits set by {@link #branch(String)} are not taken into account. * * @return list of nodes present at remote and missing locally - * @throws HgException + * @throws HgRemoteConnectionException when failed to communicate with remote repository * @throws CancelledException */ - public List executeLite() throws HgException, CancelledException { + public List executeLite() throws HgRemoteConnectionException, CancelledException { LinkedHashSet result = new LinkedHashSet(); RepositoryComparator repoCompare = getComparator(); for (BranchChain bc : getMissingBranches()) { @@ -121,10 +120,12 @@ /** * Full information about incoming changes * - * @throws HgException + * @throws HgRemoteConnectionException when failed to communicate with remote repository + * @throws HgInvalidFileException to indicate failure working with locally downloaded changes in a bundle file + * @throws HgCallbackTargetException to re-throw exception from the handler * @throws CancelledException */ - public void executeFull(final HgChangesetHandler handler) throws HgException/*FIXME specific type*/, HgException, CancelledException { + public void executeFull(final HgChangesetHandler handler) throws HgRemoteConnectionException, HgInvalidFileException, HgCallbackTargetException, CancelledException { if (handler == null) { throw new IllegalArgumentException("Delegate can't be null"); } @@ -155,8 +156,6 @@ } }); transformer.checkFailure(); - } catch (IOException ex) { - throw new HgException(ex); } finally { ps.done(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgInvalidFileException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/core/HgInvalidFileException.java Fri Sep 16 05:35:32 2011 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2011 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.core; + +import java.io.File; +import java.io.IOException; + +/** + * Thrown when there are troubles working with local file. Most likely (but not necessarily) wraps IOException. Might be + * perceived as specialized IOException with optional File and other repository information. + * + * Hg4J tries to minimize chances for IOException to occur (i.e. {@link File#canRead()} is checked before attempt to + * read a file that might not exist, and doesn't use this exception to wrap each and any {@link IOException} source (e.g. + * #close() calls are unlikely to yield it), hence it is likely to address real cases when I/O error occurs. + * + * On the other hand, when a file is supposed to exist and be readable, this exception might get thrown as well to indicate + * that's not true. + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +@SuppressWarnings("serial") +public class HgInvalidFileException extends HgException { + + private File localFile; + + public HgInvalidFileException(String message, Throwable th) { + super(message, th); + } + + public HgInvalidFileException(String message, Throwable th, File file) { + super(message, th); + localFile = file; + } + + public HgInvalidFileException setFile(File file) { + assert file != null; + localFile = file; + return this; + } + + /** + * @return file object that causes troubles, or null if specific file is unknown + */ + public File getFile() { + return localFile; + } +} diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgOutgoingCommand.java --- a/src/org/tmatesoft/hg/core/HgOutgoingCommand.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgOutgoingCommand.java Fri Sep 16 05:35:32 2011 +0200 @@ -109,7 +109,7 @@ * * @param handler delegate to process changes */ - public void executeFull(final HgChangesetHandler handler) throws HgRemoteConnectionException, HgException, CancelledException { + public void executeFull(final HgChangesetHandler handler) throws HgRemoteConnectionException, HgCallbackTargetException, CancelledException { if (handler == null) { throw new IllegalArgumentException("Delegate can't be null"); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/HgRepoFacade.java --- a/src/org/tmatesoft/hg/core/HgRepoFacade.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/core/HgRepoFacade.java Fri Sep 16 05:35:32 2011 +0200 @@ -18,6 +18,7 @@ import java.io.File; +import org.tmatesoft.hg.internal.BasicSessionContext; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.repo.HgLookup; @@ -37,8 +38,17 @@ */ public class HgRepoFacade { private HgRepository repo; + private final SessionContext context; public HgRepoFacade() { + this(new BasicSessionContext(null, null)); + } + + public HgRepoFacade(SessionContext ctx) { + if (ctx == null) { + throw new IllegalArgumentException(); + } + context = ctx; } /** @@ -57,10 +67,10 @@ /** * Tries to find repository starting from the current working directory. * @return true if found valid repository - * @throws HgException in case of errors during repository initialization + * @throws HgInvalidFileException in case of errors during repository initialization */ - public boolean init() throws HgException { - repo = new HgLookup().detectFromWorkingDir(); + public boolean init() throws HgInvalidFileException { + repo = new HgLookup(context).detectFromWorkingDir(); return repo != null && !repo.isInvalid(); } @@ -69,14 +79,14 @@ * * @param repoLocation path to any folder within structure of a Mercurial repository. * @return true if found valid repository - * @throws HgException if there are errors accessing specified location + * @throws HgInvalidFileException if there are errors accessing specified location * @throws IllegalArgumentException if argument is null */ - public boolean initFrom(File repoLocation) throws HgException { + public boolean initFrom(File repoLocation) throws HgInvalidFileException { if (repoLocation == null) { throw new IllegalArgumentException(); } - repo = new HgLookup().detect(repoLocation); + repo = new HgLookup(context).detect(repoLocation); return repo != null && !repo.isInvalid(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/core/SessionContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/core/SessionContext.java Fri Sep 16 05:35:32 2011 +0200 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 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.core; + +import org.tmatesoft.hg.internal.Experimental; +import org.tmatesoft.hg.util.LogFacility; + +/** + * WORK IN PROGRESS + * + * Access to objects that might need to be shared between various distinct operations ran during the same working session + * (i.e. caches, log, etc.). It's unspecified whether session context is per repository or can span multiple repositories + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +@Experimental(reason="Work in progress") +public interface SessionContext { + LogFacility getLog(); +} diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/BasicSessionContext.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/BasicSessionContext.java Fri Sep 16 05:35:32 2011 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2011 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 org.tmatesoft.hg.core.SessionContext; +import org.tmatesoft.hg.util.LogFacility; +import org.tmatesoft.hg.util.PathPool; +import org.tmatesoft.hg.util.PathRewrite; + +/** + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class BasicSessionContext implements SessionContext { + + private PathPool pathPool; + private final LogFacility logFacility; + + public BasicSessionContext(PathPool pathFactory, LogFacility log) { + pathPool = pathFactory; + logFacility = log != null ? log : new StreamLogFacility(true, true, true, System.out); + } + + public PathPool getPathPool() { + if (pathPool == null) { + pathPool = new PathPool(new PathRewrite.Empty()); + } + return pathPool; + } + + public LogFacility getLog() { + // e.g. for exceptions that we can't handle but log (e.g. FileNotFoundException when we've checked beforehand file.canRead() + return logFacility; + } + +} diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/ConfigFile.java --- a/src/org/tmatesoft/hg/internal/ConfigFile.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/ConfigFile.java Fri Sep 16 05:35:32 2011 +0200 @@ -36,10 +36,10 @@ private List sections; private List> content; - ConfigFile() { + public ConfigFile() { } - public void addLocation(File path) { + public void addLocation(File path) throws IOException { read(path); } @@ -92,7 +92,7 @@ // TODO handle %include and %unset directives // TODO "" and lists - private void read(File f) { + private void read(File f) throws IOException { if (f == null || !f.canRead()) { return; } @@ -100,8 +100,9 @@ sections = new ArrayList(); content = new ArrayList>(); } + BufferedReader br = null; try { - BufferedReader br = new BufferedReader(new FileReader(f)); + br = new BufferedReader(new FileReader(f)); String line; String sectionName = ""; Map section = new LinkedHashMap(); @@ -140,12 +141,13 @@ section.put(key, value); } } - br.close(); - } catch (IOException ex) { - ex.printStackTrace(); // XXX shall outer world care? + } finally { + ((ArrayList) sections).trimToSize(); + ((ArrayList) content).trimToSize(); + if (br != null) { + br.close(); + } } - ((ArrayList) sections).trimToSize(); - ((ArrayList) content).trimToSize(); assert sections.size() == content.size(); } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/DataAccessProvider.java --- a/src/org/tmatesoft/hg/internal/DataAccessProvider.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/DataAccessProvider.java Fri Sep 16 05:35:32 2011 +0200 @@ -24,6 +24,7 @@ import java.nio.channels.FileChannel; import org.tmatesoft.hg.core.HgBadStateException; +import org.tmatesoft.hg.core.SessionContext; /** * @@ -34,12 +35,14 @@ private final int mapioMagicBoundary; private final int bufferSize; + private final SessionContext context; - public DataAccessProvider() { - this(100 * 1024, 8 * 1024); + public DataAccessProvider(SessionContext ctx) { + this(ctx, 100 * 1024, 8 * 1024); } - public DataAccessProvider(int mapioBoundary, int regularBufferSize) { + public DataAccessProvider(SessionContext ctx, int mapioBoundary, int regularBufferSize) { + context = ctx; mapioMagicBoundary = mapioBoundary; bufferSize = regularBufferSize; } @@ -67,7 +70,7 @@ } } catch (IOException ex) { // unlikely to happen, we've made sure file exists. - ex.printStackTrace(); // FIXME log error + context.getLog().error(getClass(), ex, null); } return new DataAccess(); // non-null, empty. } @@ -177,7 +180,7 @@ try { fileChannel.close(); } catch (IOException ex) { - ex.printStackTrace(); // log debug + StreamLogFacility.newDefault().debug(getClass(), ex, null); } fileChannel = null; } @@ -298,7 +301,7 @@ try { fileChannel.close(); } catch (IOException ex) { - ex.printStackTrace(); // log debug + StreamLogFacility.newDefault().debug(getClass(), ex, null); } fileChannel = null; } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/DigestHelper.java --- a/src/org/tmatesoft/hg/internal/DigestHelper.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/DigestHelper.java Fri Sep 16 05:35:32 2011 +0200 @@ -21,6 +21,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import org.tmatesoft.hg.core.HgBadStateException; import org.tmatesoft.hg.core.Nodeid; @@ -49,7 +50,7 @@ sha1 = MessageDigest.getInstance("SHA-1"); } catch (NoSuchAlgorithmException ex) { // could hardly happen, JDK from Sun always has sha1. - ex.printStackTrace(); // FIXME log error + throw new HgBadStateException(ex); } } return sha1; diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/Internals.java --- a/src/org/tmatesoft/hg/internal/Internals.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/Internals.java Fri Sep 16 05:35:32 2011 +0200 @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; +import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.util.PathRewrite; @@ -41,6 +42,15 @@ public Internals() { } + + public void parseRequires(HgRepository hgRepo, File requiresFile) { + try { + new RequiresFile().parse(this, requiresFile); + } catch (IOException ex) { + // FIXME not quite sure error reading requires file shall be silently logged only. + HgInternals.getContext(hgRepo).getLog().error(getClass(), ex, null); + } + } public/*for tests, otherwise pkg*/ void setStorageConfig(int version, int flags) { requiresFlags = flags; @@ -63,10 +73,6 @@ } } - public ConfigFile newConfigFile() { - return new ConfigFile(); - } - public List getFilters(HgRepository hgRepo, ConfigFile cfg) { if (filterFactories == null) { filterFactories = new ArrayList(); diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/NewlineFilter.java --- a/src/org/tmatesoft/hg/internal/NewlineFilter.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/NewlineFilter.java Fri Sep 16 05:35:32 2011 +0200 @@ -23,10 +23,12 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Map; +import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.util.Path; @@ -177,7 +179,11 @@ // } // XXX perhaps, add HgDataFile.hasWorkingCopy and workingCopyContent()? ConfigFile hgeol = new ConfigFile(); - hgeol.addLocation(cfgFile); + try { + hgeol.addLocation(cfgFile); + } catch (IOException ex) { + HgInternals.getContext(hgRepo).getLog().warn(getClass(), ex, null); + } nativeRepoFormat = hgeol.getSection("repository").get("native"); if (nativeRepoFormat == null) { nativeRepoFormat = "LF"; @@ -199,7 +205,7 @@ } else if ("BIN".equals(e.getValue())) { binPatterns.add(e.getKey()); } else { - System.out.printf("Can't recognize .hgeol entry: %s for %s", e.getValue(), e.getKey()); // FIXME log warning + HgInternals.getContext(hgRepo).getLog().warn(getClass(), "Can't recognize .hgeol entry: %s for %s", e.getValue(), e.getKey()); } } if (!crlfPatterns.isEmpty()) { diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/PathGlobMatcher.java --- a/src/org/tmatesoft/hg/internal/PathGlobMatcher.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/PathGlobMatcher.java Fri Sep 16 05:35:32 2011 +0200 @@ -44,7 +44,6 @@ try { delegate = new PathRegexpMatcher(regexp); } catch (PatternSyntaxException ex) { - ex.printStackTrace(); throw new IllegalArgumentException(ex); } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/RepositoryComparator.java --- a/src/org/tmatesoft/hg/internal/RepositoryComparator.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/RepositoryComparator.java Fri Sep 16 05:35:32 2011 +0200 @@ -30,7 +30,6 @@ import java.util.Set; import org.tmatesoft.hg.core.HgBadStateException; -import org.tmatesoft.hg.core.HgException; import org.tmatesoft.hg.core.HgRemoteConnectionException; import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.repo.HgChangelog; @@ -393,7 +392,7 @@ /** * @return list of nodeids from branchRoot to branchHead, inclusive. IOW, first element of the list is always root of the branch */ - public List completeBranch(final Nodeid branchRoot, final Nodeid branchHead) throws HgException { + public List completeBranch(final Nodeid branchRoot, final Nodeid branchHead) throws HgRemoteConnectionException { class DataEntry { public final Nodeid queryHead; public final int headIndex; @@ -512,7 +511,7 @@ * returns in order from branch root to head * for a non-empty BranchChain, shall return modifiable list */ - public List visitBranches(BranchChain bc) throws HgException { + public List visitBranches(BranchChain bc) throws HgRemoteConnectionException { if (bc == null) { return Collections.emptyList(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/RequiresFile.java --- a/src/org/tmatesoft/hg/internal/RequiresFile.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/RequiresFile.java Fri Sep 16 05:35:32 2011 +0200 @@ -35,16 +35,17 @@ public RequiresFile() { } - public void parse(Internals repoImpl, File requiresFile) { + public void parse(Internals repoImpl, File requiresFile) throws IOException { if (!requiresFile.exists()) { return; } + BufferedReader br = null; try { boolean revlogv1 = false; boolean store = false; boolean fncache = false; boolean dotencode = false; - BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(requiresFile))); + br = new BufferedReader(new InputStreamReader(new FileInputStream(requiresFile))); String line; while ((line = br.readLine()) != null) { revlogv1 |= "revlogv1".equals(line); @@ -57,9 +58,10 @@ flags += fncache ? FNCACHE : 0; flags += dotencode ? DOTENCODE : 0; repoImpl.setStorageConfig(revlogv1 ? 1 : 0, flags); - br.close(); - } catch (IOException ex) { - ex.printStackTrace(); // FIXME log + } finally { + if (br != null) { + br.close(); + } } } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/RevlogStream.java --- a/src/org/tmatesoft/hg/internal/RevlogStream.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/RevlogStream.java Fri Sep 16 05:35:32 2011 +0200 @@ -79,6 +79,9 @@ return baseRevisions.length; } + /** + * @throws HgBadStateException if internal read operation failed + */ public int dataLength(int revision) { // XXX in fact, use of iterate() instead of this implementation may be quite reasonable. // @@ -94,12 +97,15 @@ return actualLen; } catch (IOException ex) { ex.printStackTrace(); // log error. FIXME better handling - throw new IllegalStateException(ex); + throw new HgBadStateException(ex); } finally { daIndex.done(); } } + /** + * @throws HgBadStateException if internal read operation failed + */ public byte[] nodeid(int revision) { final int indexSize = revisionCount(); if (revision == TIP) { @@ -117,12 +123,16 @@ return rv; } catch (IOException ex) { ex.printStackTrace(); - throw new IllegalStateException(); + throw new HgBadStateException(); } finally { daIndex.done(); } } - + + /** + * Get link field from the index record. + * @throws HgBadStateException if internal read operation failed + */ public int linkRevision(int revision) { final int last = revisionCount() - 1; if (revision == TIP) { @@ -139,7 +149,7 @@ return linkRev; } catch (IOException ex) { ex.printStackTrace(); - throw new IllegalStateException(); + throw new HgBadStateException(); } finally { daIndex.done(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/StreamLogFacility.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/StreamLogFacility.java Fri Sep 16 05:35:32 2011 +0200 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011 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.PrintStream; + +import org.tmatesoft.hg.util.LogFacility; + +/** + * Primitive implementation of {@link LogFacility} that directs all output to specified {@link PrintStream}. + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class StreamLogFacility implements LogFacility { + + private final boolean isDebug; + private final boolean isInfo; + protected final boolean timestamp; + protected final PrintStream outStream; + + public StreamLogFacility(boolean pringDebug, boolean printInfo, boolean needTimestamp, PrintStream out) { + isDebug = pringDebug; + isInfo = printInfo; + timestamp = needTimestamp; + outStream = out; + } + + public boolean isDebug() { + return isDebug; + } + + public boolean isInfo() { + return isInfo; + } + + public void debug(Class src, String format, Object... args) { + if (!isDebug) { + return; + } + printf("DEBUG", src, format, args); + } + + public void info(Class src, String format, Object... args) { + if (!isInfo) { + return; + } + printf("INFO", src, format, args); + } + + public void warn(Class src, String format, Object... args) { + printf("WARN", src, format, args); + } + + public void error(Class src, String format, Object... args) { + printf("ERROR", src, format, args); + } + + public void debug(Class src, Throwable th, String message) { + if (!isDebug) { + return; + } + printf("DEBUG", src, th, message); + } + + public void info(Class src, Throwable th, String message) { + if (!isInfo) { + return; + } + printf("INFO", src, th, message); + } + + public void warn(Class src, Throwable th, String message) { + printf("WARN", src, th, message); + } + + public void error(Class src, Throwable th, String message) { + printf("ERROR", src, th, message); + } + + protected void printf(String level, Class src, String format, Object... args) { + String msg = String.format(format, args); + if (timestamp) { + outStream.printf(isDebug ? "%tT.%1$tL " : "%tT ", System.currentTimeMillis()); + } + if (isDebug) { + String cn = src.getName(); + if (cn.startsWith("org.tmatesoft.hg.")) { + cn = "oth." + cn.substring("org.tmatesoft.hg.".length()); + } + outStream.printf("(%s) ", cn); + } + outStream.printf("%s: %s", level, msg); + if (format.length() == 0 || format.charAt(format.length() - 1) != '\n') { + outStream.println(); + } + } + protected void printf(String level, Class src, Throwable th, String msg) { + if (msg != null || timestamp || isDebug || th == null) { + printf(level, src, msg == null ? "" : msg, (Object[]) null); + } + if (th != null) { + if (isDebug || isInfo) { + // full stack trace + th.printStackTrace(outStream); + } else { + // just title of the exception + outStream.printf("%s: %s\n", th.getClass().getName(), th.getMessage()); + } + } + } + + // alternative to hardcore System.out where SessionContext is not available now (or ever) + public static LogFacility newDefault() { + return new StreamLogFacility(true, true, true, System.out); + } +} diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/internal/SubrepoManager.java --- a/src/org/tmatesoft/hg/internal/SubrepoManager.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/internal/SubrepoManager.java Fri Sep 16 05:35:32 2011 +0200 @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; +import org.tmatesoft.hg.repo.HgInternals; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.repo.HgSubrepoLocation; @@ -61,7 +62,7 @@ BufferedReader br = new BufferedReader(new FileReader(hgsubFile)); return readConfig(br, state); } catch (IOException ex) { - ex.printStackTrace(); // XXX log. Generally, shall not happen + HgInternals.getContext(repo).getLog().error(getClass(), ex, "Subrepo state read failed"); } return Collections.emptyList(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgBranches.java --- a/src/org/tmatesoft/hg/repo/HgBranches.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgBranches.java Fri Sep 16 05:35:32 2011 +0200 @@ -89,13 +89,13 @@ } return lastInCache; } catch (IOException ex) { - ex.printStackTrace(); // XXX log error, but otherwise do nothing + repo.getContext().getLog().warn(getClass(), ex, null); // log error, but otherwise do nothing } finally { if (br != null) { try { br.close(); } catch (IOException ex) { - ex.printStackTrace(); // ignore + repo.getContext().getLog().info(getClass(), ex, null); // ignore } } } @@ -283,9 +283,8 @@ } } bw.close(); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); + } catch (IOException ex) { + repo.getContext().getLog().error(getClass(), ex, "Error writing branch cache file"); } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgBundle.java --- a/src/org/tmatesoft/hg/repo/HgBundle.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgBundle.java Fri Sep 16 05:35:32 2011 +0200 @@ -23,6 +23,7 @@ import org.tmatesoft.hg.core.HgBadStateException; import org.tmatesoft.hg.core.HgException; +import org.tmatesoft.hg.core.HgInvalidFileException; import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.internal.ByteArrayChannel; import org.tmatesoft.hg.internal.ByteArrayDataAccess; @@ -93,7 +94,7 @@ * @param hgRepo repository that shall possess base revision for this bundle * @param inspector callback to get each changeset found */ - public void changes(final HgRepository hgRepo, final HgChangelog.Inspector inspector) throws HgException, IOException { + public void changes(final HgRepository hgRepo, final HgChangelog.Inspector inspector) throws HgInvalidFileException { Inspector bundleInsp = new Inspector() { DigestHelper dh = new DigestHelper(); boolean emptyChangelog = true; @@ -180,7 +181,7 @@ inspectChangelog(bundleInsp); } - public void dump() throws IOException { + public void dump() throws HgException { Dump dump = new Dump(); inspectAll(dump); System.out.println("Total files:" + dump.names.size()); @@ -246,40 +247,51 @@ } } - public void inspectChangelog(Inspector inspector) throws IOException { + public void inspectChangelog(Inspector inspector) throws HgInvalidFileException { if (inspector == null) { throw new IllegalArgumentException(); } - DataAccess da = getDataStream(); + DataAccess da = null; try { + da = getDataStream(); internalInspectChangelog(da, inspector); + } catch (IOException ex) { + throw new HgInvalidFileException("Bundle.inspectChangelog failed", ex, bundleFile); } finally { - da.done(); + if (da != null) { + da.done(); + } } } - public void inspectManifest(Inspector inspector) throws IOException { + public void inspectManifest(Inspector inspector) throws HgInvalidFileException { if (inspector == null) { throw new IllegalArgumentException(); } - DataAccess da = getDataStream(); + DataAccess da = null; try { + da = getDataStream(); if (da.isEmpty()) { return; } skipGroup(da); // changelog internalInspectManifest(da, inspector); + } catch (IOException ex) { + throw new HgInvalidFileException("Bundle.inspectManifest failed", ex, bundleFile); } finally { - da.done(); + if (da != null) { + da.done(); + } } } - public void inspectFiles(Inspector inspector) throws IOException { + public void inspectFiles(Inspector inspector) throws HgInvalidFileException { if (inspector == null) { throw new IllegalArgumentException(); } - DataAccess da = getDataStream(); + DataAccess da = null; try { + da = getDataStream(); if (da.isEmpty()) { return; } @@ -289,22 +301,31 @@ } skipGroup(da); // manifest internalInspectFiles(da, inspector); + } catch (IOException ex) { + throw new HgInvalidFileException("Bundle.inspectFiles failed", ex, bundleFile); } finally { - da.done(); + if (da != null) { + da.done(); + } } } - public void inspectAll(Inspector inspector) throws IOException { + public void inspectAll(Inspector inspector) throws HgInvalidFileException { if (inspector == null) { throw new IllegalArgumentException(); } - DataAccess da = getDataStream(); + DataAccess da = null; try { + da = getDataStream(); internalInspectChangelog(da, inspector); internalInspectManifest(da, inspector); internalInspectFiles(da, inspector); + } catch (IOException ex) { + throw new HgInvalidFileException("Bundle.inspectAll failed", ex, bundleFile); } finally { - da.done(); + if (da != null) { + da.done(); + } } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgDataFile.java --- a/src/org/tmatesoft/hg/repo/HgDataFile.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDataFile.java Fri Sep 16 05:35:32 2011 +0200 @@ -139,7 +139,7 @@ try { fc.close(); } catch (IOException ex) { - ex.printStackTrace(); + getRepo().getContext().getLog().info(getClass(), ex, null); } } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgDirstate.java --- a/src/org/tmatesoft/hg/repo/HgDirstate.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDirstate.java Fri Sep 16 05:35:32 2011 +0200 @@ -144,7 +144,8 @@ } } } catch (IOException ex) { - ex.printStackTrace(); // FIXME log error, clean dirstate? + repo.getContext().getLog().error(getClass(), ex, null); + // FIXME clean dirstate? } finally { da.done(); } @@ -218,7 +219,7 @@ branch = b == null || b.length() == 0 ? HgRepository.DEFAULT_BRANCH_NAME : b; r.close(); } catch (IOException ex) { - ex.printStackTrace(); // XXX log verbose debug, exception might be legal here (i.e. FileNotFound) + repo.getContext().getLog().debug(HgDirstate.class, ex, null); // log verbose debug, exception might be legal here (i.e. FileNotFound) // IGNORE } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgInternals.java --- a/src/org/tmatesoft/hg/repo/HgInternals.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgInternals.java Fri Sep 16 05:35:32 2011 +0200 @@ -25,6 +25,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; +import org.tmatesoft.hg.core.SessionContext; import org.tmatesoft.hg.internal.ConfigFile; import org.tmatesoft.hg.internal.Experimental; import org.tmatesoft.hg.internal.RelativePathRewrite; @@ -114,6 +115,11 @@ // path caching is better to be done in the code which knows that path are being reused return new FileWalker(repoRoot, pathSrc, workindDirScope); } + + // expose othewise package-local information primarily to use in our own o.t.hg.core package + public static SessionContext getContext(HgRepository repo) { + return repo.getContext(); + } // Convenient check of local revision number for validity (not all negative values are wrong as long as we use negative constants) diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgLookup.java --- a/src/org/tmatesoft/hg/repo/HgLookup.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgLookup.java Fri Sep 16 05:35:32 2011 +0200 @@ -22,10 +22,11 @@ import java.net.URL; import org.tmatesoft.hg.core.HgBadArgumentException; -import org.tmatesoft.hg.core.HgException; +import org.tmatesoft.hg.core.HgInvalidFileException; +import org.tmatesoft.hg.core.SessionContext; +import org.tmatesoft.hg.internal.BasicSessionContext; import org.tmatesoft.hg.internal.ConfigFile; import org.tmatesoft.hg.internal.DataAccessProvider; -import org.tmatesoft.hg.internal.Internals; /** * Utility methods to find Mercurial repository at a given location @@ -36,17 +37,25 @@ public class HgLookup { private ConfigFile globalCfg; + private SessionContext sessionContext; + + public HgLookup() { + } + + public HgLookup(SessionContext ctx) { + sessionContext = ctx; + } - public HgRepository detectFromWorkingDir() throws HgException { + public HgRepository detectFromWorkingDir() throws HgInvalidFileException { return detect(System.getProperty("user.dir")); } - public HgRepository detect(String location) throws HgException { + public HgRepository detect(String location) throws HgInvalidFileException { return detect(new File(location)); } // look up in specified location and above - public HgRepository detect(File location) throws HgException { + public HgRepository detect(File location) throws HgInvalidFileException { File dir = location.getAbsoluteFile(); File repository; do { @@ -64,17 +73,17 @@ } try { String repoPath = repository.getParentFile().getCanonicalPath(); - return new HgRepository(repoPath, repository); + return new HgRepository(getContext(), repoPath, repository); } catch (IOException ex) { - throw new HgException(location.toString(), ex); + throw new HgInvalidFileException(location.toString(), ex, location); } } - public HgBundle loadBundle(File location) /*XXX perhaps, HgDataStreamException or anything like HgMalformedDataException? Or RuntimeEx is better?*/{ + public HgBundle loadBundle(File location) throws HgInvalidFileException { if (location == null || !location.canRead()) { - throw new IllegalArgumentException(); + throw new HgInvalidFileException(String.format("Can't read file %s", location == null ? null : location.getPath()), null, location); } - return new HgBundle(new DataAccessProvider(), location).link(); + return new HgBundle(new DataAccessProvider(getContext()), location).link(); } /** @@ -105,24 +114,36 @@ throw new HgBadArgumentException(String.format("Found %s server spec in the config, but failed to initialize with it", key), ex); } } - return new HgRemoteRepository(url); + return new HgRemoteRepository(getContext(), url); } - public HgRemoteRepository detect(URL url) throws HgException { + public HgRemoteRepository detect(URL url) throws HgBadArgumentException { if (url == null) { throw new IllegalArgumentException(); } if (Boolean.FALSE.booleanValue()) { throw HgRepository.notImplemented(); } - return new HgRemoteRepository(url); + return new HgRemoteRepository(getContext(), url); } private ConfigFile getGlobalConfig() { if (globalCfg == null) { - globalCfg = new Internals().newConfigFile(); - globalCfg.addLocation(new File(System.getProperty("user.home"), ".hgrc")); + globalCfg = new ConfigFile(); + try { + globalCfg.addLocation(new File(System.getProperty("user.home"), ".hgrc")); + } catch (IOException ex) { + // XXX perhaps, makes sense to let caller/client know that we've failed to read global config? + getContext().getLog().warn(getClass(), ex, null); + } } return globalCfg; } + + private SessionContext getContext() { + if (sessionContext == null) { + sessionContext = new BasicSessionContext(null, null); + } + return sessionContext; + } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgRemoteRepository.java --- a/src/org/tmatesoft/hg/repo/HgRemoteRepository.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgRemoteRepository.java Fri Sep 16 05:35:32 2011 +0200 @@ -48,8 +48,10 @@ import org.tmatesoft.hg.core.HgBadArgumentException; import org.tmatesoft.hg.core.HgBadStateException; +import org.tmatesoft.hg.core.HgInvalidFileException; import org.tmatesoft.hg.core.HgRemoteConnectionException; import org.tmatesoft.hg.core.Nodeid; +import org.tmatesoft.hg.core.SessionContext; /** * WORK IN PROGRESS, DO NOT USE @@ -66,12 +68,14 @@ private final String authInfo; private final boolean debug = Boolean.parseBoolean(System.getProperty("hg4j.remote.debug")); private HgLookup lookupHelper; + private final SessionContext sessionContext; - HgRemoteRepository(URL url) throws HgBadArgumentException { - if (url == null) { + HgRemoteRepository(SessionContext ctx, URL url) throws HgBadArgumentException { + if (url == null || ctx == null) { throw new IllegalArgumentException(); } this.url = url; + sessionContext = ctx; if ("https".equals(url.getProtocol())) { try { sslContext = SSLContext.getInstance("SSL"); @@ -322,7 +326,7 @@ * (there's no header like HG10?? with the server output, though, * as one may expect according to http://mercurial.selenic.com/wiki/BundleFormat) */ - public HgBundle getChanges(List roots) throws HgRemoteConnectionException { + public HgBundle getChanges(List roots) throws HgRemoteConnectionException, HgInvalidFileException { List _roots = roots.isEmpty() ? Collections.singletonList(Nodeid.NULL) : roots; StringBuilder sb = new StringBuilder(20 + _roots.size() * 41); sb.append("roots="); @@ -361,7 +365,7 @@ private HgLookup getLookupHelper() { if (lookupHelper == null) { - lookupHelper = new HgLookup(); + lookupHelper = new HgLookup(sessionContext); } return lookupHelper; } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgRepository.java --- a/src/org/tmatesoft/hg/repo/HgRepository.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Fri Sep 16 05:35:32 2011 +0200 @@ -27,13 +27,13 @@ import org.tmatesoft.hg.core.HgDataStreamException; import org.tmatesoft.hg.core.Nodeid; +import org.tmatesoft.hg.core.SessionContext; import org.tmatesoft.hg.internal.ByteArrayChannel; import org.tmatesoft.hg.internal.ConfigFile; import org.tmatesoft.hg.internal.DataAccessProvider; import org.tmatesoft.hg.internal.Experimental; import org.tmatesoft.hg.internal.Filter; import org.tmatesoft.hg.internal.Internals; -import org.tmatesoft.hg.internal.RequiresFile; import org.tmatesoft.hg.internal.RevlogStream; import org.tmatesoft.hg.internal.SubrepoManager; import org.tmatesoft.hg.util.CancelledException; @@ -73,6 +73,7 @@ private final PathRewrite dataPathHelper; private final PathRewrite repoPathHelper; private final boolean isCaseSensitiveFileSystem; + private final SessionContext sessionContext; private HgChangelog changelog; private HgManifest manifest; @@ -95,20 +96,23 @@ dataAccess = null; dataPathHelper = repoPathHelper = null; normalizePath = null; + sessionContext = null; isCaseSensitiveFileSystem = !Internals.runningOnWindows(); } - HgRepository(String repositoryPath, File repositoryRoot) { + HgRepository(SessionContext ctx, String repositoryPath, File repositoryRoot) { assert ".hg".equals(repositoryRoot.getName()) && repositoryRoot.isDirectory(); assert repositoryPath != null; assert repositoryRoot != null; + assert ctx != null; repoDir = repositoryRoot; workingDir = repoDir.getParentFile(); if (workingDir == null) { throw new IllegalArgumentException(repoDir.toString()); } repoLocation = repositoryPath; - dataAccess = new DataAccessProvider(); + sessionContext = ctx; + dataAccess = new DataAccessProvider(ctx); final boolean runningOnWindows = Internals.runningOnWindows(); isCaseSensitiveFileSystem = !runningOnWindows; if (runningOnWindows) { @@ -127,7 +131,7 @@ } else { normalizePath = new PathRewrite.Empty(); // or strip leading slash, perhaps? } - parseRequires(); + impl.parseRequires(this, new File(repoDir, "requires")); dataPathHelper = impl.buildDataFilesHelper(); repoPathHelper = impl.buildRepositoryFilesHelper(); } @@ -176,20 +180,23 @@ final String content = new String(sink.toArray(), "UTF8"); tags.readGlobal(new StringReader(content)); } catch (CancelledException ex) { - ex.printStackTrace(); // IGNORE, can't happen, we did not configure cancellation + // IGNORE, can't happen, we did not configure cancellation + getContext().getLog().debug(getClass(), ex, null); } catch (HgDataStreamException ex) { - ex.printStackTrace(); // FIXME need to react + getContext().getLog().error(getClass(), ex, null); + // FIXME need to react } catch (IOException ex) { // UnsupportedEncodingException can't happen (UTF8) // only from readGlobal. Need to reconsider exceptions thrown from there - ex.printStackTrace(); // XXX need to decide what to do this. failure to read single revision shall not break complete cycle + getContext().getLog().error(getClass(), ex, null); + // XXX need to decide what to do this. failure to read single revision shall not break complete cycle } } } tags.readGlobal(new File(getWorkingDir(), ".hgtags")); // XXX replace with HgDataFile.workingCopy tags.readLocal(new File(repoDir, "localtags")); } catch (IOException ex) { - ex.printStackTrace(); // FIXME log or othewise report + getContext().getLog().error(getClass(), ex, null); } } return tags; @@ -302,7 +309,7 @@ File ignoreFile = new File(getWorkingDir(), ".hgignore"); ignore.read(ignoreFile); } catch (IOException ex) { - ex.printStackTrace(); // log warn + getContext().getLog().warn(getClass(), ex, null); } } return ignore; @@ -334,7 +341,7 @@ fake.deleteOnExit(); return new RevlogStream(dataAccess, fake); } catch (IOException ex) { - ex.printStackTrace(); // FIXME report in debug + getContext().getLog().info(getClass(), ex, null); } } } @@ -344,11 +351,15 @@ // can't expose internal class, otherwise seems reasonable to have it in API /*package-local*/ ConfigFile getConfigFile() { if (configFile == null) { - configFile = impl.newConfigFile(); - configFile.addLocation(new File(System.getProperty("user.home"), ".hgrc")); - // last one, overrides anything else - // /.hg/hgrc - configFile.addLocation(new File(getRepositoryRoot(), "hgrc")); + configFile = new ConfigFile(); + try { + configFile.addLocation(new File(System.getProperty("user.home"), ".hgrc")); + // last one, overrides anything else + // /.hg/hgrc + configFile.addLocation(new File(getRepositoryRoot(), "hgrc")); + } catch (IOException ex) { + getContext().getLog().warn(getClass(), ex, "Errors while reading user configuration file"); + } } return configFile; } @@ -364,6 +375,10 @@ /*package-local*/ File getFile(HgDataFile dataFile) { return new File(getWorkingDir(), dataFile.getPath().toString()); } + + /*package-local*/ SessionContext getContext() { + return sessionContext; + } private List instantiateFilters(Path p, Filter.Options opts) { List factories = impl.getFilters(this, getConfigFile()); @@ -379,9 +394,4 @@ } return rv; } - - private void parseRequires() { - new RequiresFile().parse(impl, new File(repoDir, "requires")); - } - } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgSubrepoLocation.java --- a/src/org/tmatesoft/hg/repo/HgSubrepoLocation.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgSubrepoLocation.java Fri Sep 16 05:35:32 2011 +0200 @@ -19,7 +19,7 @@ import java.io.File; import org.tmatesoft.hg.core.HgBadStateException; -import org.tmatesoft.hg.core.HgException; +import org.tmatesoft.hg.core.HgInvalidFileException; import org.tmatesoft.hg.internal.Experimental; import org.tmatesoft.hg.util.Path; @@ -86,7 +86,7 @@ return owner; } - public HgRepository getRepo() throws HgException { + public HgRepository getRepo() throws HgInvalidFileException { if (kind != Kind.Hg) { throw new HgBadStateException(); } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgTags.java --- a/src/org/tmatesoft/hg/repo/HgTags.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgTags.java Fri Sep 16 05:35:32 2011 +0200 @@ -107,7 +107,7 @@ continue; } if (line.length() < 40+2 /*nodeid, space and at least single-char tagname*/) { - System.out.println("Bad tags line:" + line); // FIXME log or otherwise report (IStatus analog?) + repo.getContext().getLog().warn(getClass(), "Bad tags line: %s", line); continue; } int spacePos = line.indexOf(' '); @@ -151,7 +151,7 @@ } } else { - System.out.println("Bad tags line:" + line); // FIXME see above + repo.getContext().getLog().warn(getClass(), "Bad tags line: %s", line); } } } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java --- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Fri Sep 16 05:35:32 2011 +0200 @@ -397,59 +397,61 @@ private boolean areTheSame(FileInfo f, final byte[] data, Path p) { ReadableByteChannel is = null; - try { - try { - is = f.newInputChannel(); - ByteBuffer fb = ByteBuffer.allocate(min(1 + data.length * 2 /*to fit couple of lines appended; never zero*/, 8192)); - class Check implements ByteChannel { - final boolean debug = false; // XXX may want to add global variable to allow clients to turn - boolean sameSoFar = true; - int x = 0; + class Check implements ByteChannel { + final boolean debug = repo.getContext().getLog().isDebug(); + boolean sameSoFar = true; + int x = 0; - public int write(ByteBuffer buffer) { - for (int i = buffer.remaining(); i > 0; i--, x++) { - if (x >= data.length /*file has been appended*/ || data[x] != buffer.get()) { - if (debug) { - byte[] xx = new byte[15]; - if (buffer.position() > 5) { - buffer.position(buffer.position() - 5); - } - buffer.get(xx); - System.out.print("expected >>" + new String(data, max(0, x - 4), 20) + "<< but got >>"); - System.out.println(new String(xx) + "<<"); - } - sameSoFar = false; - break; + public int write(ByteBuffer buffer) { + for (int i = buffer.remaining(); i > 0; i--, x++) { + if (x >= data.length /*file has been appended*/ || data[x] != buffer.get()) { + if (debug) { + byte[] xx = new byte[15]; + if (buffer.position() > 5) { + buffer.position(buffer.position() - 5); } + buffer.get(xx, 0, min(xx.length, i)); + repo.getContext().getLog().debug(getClass(), "expected >>%s<< but got >>%s<<", new String(data, max(0, x - 4), min(data.length - x, 20)), new String(xx)); } - buffer.position(buffer.limit()); // mark as read - return buffer.limit(); - } - - public boolean sameSoFar() { - return sameSoFar; - } - public boolean ultimatelyTheSame() { - return sameSoFar && x == data.length; + sameSoFar = false; + break; } - }; - Check check = new Check(); - FilterByteChannel filters = new FilterByteChannel(check, repo.getFiltersFromWorkingDirToRepo(p)); - while (is.read(fb) != -1 && check.sameSoFar()) { - fb.flip(); - filters.write(fb); - fb.compact(); } - return check.ultimatelyTheSame(); - } catch (IOException ex) { - ex.printStackTrace(); // log warn - } finally { - if (is != null) { + buffer.position(buffer.limit()); // mark as read + return buffer.limit(); + } + + public boolean sameSoFar() { + return sameSoFar; + } + public boolean ultimatelyTheSame() { + return sameSoFar && x == data.length; + } + }; + Check check = new Check(); + try { + is = f.newInputChannel(); + ByteBuffer fb = ByteBuffer.allocate(min(1 + data.length * 2 /*to fit couple of lines appended; never zero*/, 8192)); + FilterByteChannel filters = new FilterByteChannel(check, repo.getFiltersFromWorkingDirToRepo(p)); + while (is.read(fb) != -1 && check.sameSoFar()) { + fb.flip(); + filters.write(fb); + fb.compact(); + } + return check.ultimatelyTheSame(); + } catch (CancelledException ex) { + repo.getContext().getLog().warn(getClass(), ex, "Unexpected cancellation"); + return check.ultimatelyTheSame(); + } catch (IOException ex) { + repo.getContext().getLog().warn(getClass(), ex, null); + } finally { + if (is != null) { + try { is.close(); + } catch (IOException ex) { + repo.getContext().getLog().info(getClass(), ex, null); } } - } catch (/*TODO typed*/Exception ex) { - ex.printStackTrace(); } return false; } diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/util/LogFacility.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/util/LogFacility.java Fri Sep 16 05:35:32 2011 +0200 @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2011 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.util; + +import org.tmatesoft.hg.internal.Experimental; + +/** + * WORK IN PROGRESS + * + * Intention of this class is to abstract away almost any log facility out there clients might be using with the Hg4J library, + * not to be a full-fledged logging facility of its own. + * + * Implementations may wrap platform- or application-specific loggers, e.g. {@link java.util.logging.Logger} or + * org.eclipse.core.runtime.ILog + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +@Experimental(reason="API might get changed") +public interface LogFacility { + + boolean isDebug(); + boolean isInfo(); + + // src and format never null + void debug(Class src, String format, Object... args); + void info(Class src, String format, Object... args); + void warn(Class src, String format, Object... args); + void error(Class src, String format, Object... args); + + // src shall be non null, either th or message or both + void debug(Class src, Throwable th, String message); + void info(Class src, Throwable th, String message); + void warn(Class src, Throwable th, String message); + void error(Class src, Throwable th, String message); +} diff -r 32890bab7209 -r 981f9f50bb6c src/org/tmatesoft/hg/util/RegularFileInfo.java --- a/src/org/tmatesoft/hg/util/RegularFileInfo.java Wed Sep 14 04:41:57 2011 +0200 +++ b/src/org/tmatesoft/hg/util/RegularFileInfo.java Fri Sep 16 05:35:32 2011 +0200 @@ -23,6 +23,8 @@ import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; +import org.tmatesoft.hg.internal.StreamLogFacility; + /** * * @author Artem Tikhomirov @@ -54,7 +56,7 @@ try { return new FileInputStream(file).getChannel(); } catch (FileNotFoundException ex) { - ex.printStackTrace(); // FIXME log debug. + StreamLogFacility.newDefault().debug(getClass(), ex, null); // shall not happen, provided this class is used correctly return new ReadableByteChannel() {