Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/WorkingDirFileWriter.java @ 705:b4242b7e7dfe
Merge command: implement conflict resolution alternatives
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 15 Aug 2013 18:43:50 +0200 |
parents | 6526d8adbc0f |
children | 42b88709e41d |
comparison
equal
deleted
inserted
replaced
704:7743a9c10bfa | 705:b4242b7e7dfe |
---|---|
19 import static org.tmatesoft.hg.util.LogFacility.Severity.Warn; | 19 import static org.tmatesoft.hg.util.LogFacility.Severity.Warn; |
20 | 20 |
21 import java.io.File; | 21 import java.io.File; |
22 import java.io.FileOutputStream; | 22 import java.io.FileOutputStream; |
23 import java.io.IOException; | 23 import java.io.IOException; |
24 import java.io.InputStream; | |
24 import java.nio.ByteBuffer; | 25 import java.nio.ByteBuffer; |
25 import java.nio.channels.FileChannel; | 26 import java.nio.channels.FileChannel; |
26 | 27 |
28 import org.tmatesoft.hg.core.HgFileRevision; | |
29 import org.tmatesoft.hg.core.HgIOException; | |
27 import org.tmatesoft.hg.repo.HgDataFile; | 30 import org.tmatesoft.hg.repo.HgDataFile; |
28 import org.tmatesoft.hg.repo.HgManifest; | 31 import org.tmatesoft.hg.repo.HgManifest; |
29 import org.tmatesoft.hg.repo.HgRuntimeException; | 32 import org.tmatesoft.hg.repo.HgRuntimeException; |
30 import org.tmatesoft.hg.util.ByteChannel; | 33 import org.tmatesoft.hg.util.ByteChannel; |
31 import org.tmatesoft.hg.util.CancelledException; | 34 import org.tmatesoft.hg.util.CancelledException; |
63 /** | 66 /** |
64 * Writes content of specified file revision into local filesystem, or create a symlink according to flags. | 67 * Writes content of specified file revision into local filesystem, or create a symlink according to flags. |
65 * Executable bit is set if specified and filesystem supports it. | 68 * Executable bit is set if specified and filesystem supports it. |
66 * @throws HgRuntimeException | 69 * @throws HgRuntimeException |
67 */ | 70 */ |
68 public void processFile(HgDataFile df, int fileRevIndex, HgManifest.Flags flags) throws IOException, HgRuntimeException { | 71 public void processFile(final HgDataFile df, final int fileRevIndex, HgManifest.Flags flags) throws HgIOException, HgRuntimeException { |
72 processFile(df.getPath(), new Fetch() { | |
73 public void readInto(ByteChannel ch) { | |
74 try { | |
75 df.contentWithFilters(fileRevIndex, ch); | |
76 } catch (CancelledException ex) { | |
77 handleUnexpectedCancel(ex); | |
78 } | |
79 } | |
80 }, flags); | |
81 } | |
82 | |
83 public void processFile(final HgFileRevision fr) throws HgIOException, HgRuntimeException { | |
84 processFile(fr.getPath(), new Fetch() { | |
85 | |
86 public void readInto(ByteChannel ch) throws IOException, HgRuntimeException { | |
87 try { | |
88 fr.putContentTo(ch); | |
89 } catch (CancelledException ex) { | |
90 handleUnexpectedCancel(ex); | |
91 } | |
92 } | |
93 }, fr.getFileFlags()); | |
94 } | |
95 | |
96 /** | |
97 * Closes supplied content stream | |
98 */ | |
99 public void processFile(Path fname, final InputStream content, HgManifest.Flags flags) throws HgIOException, HgRuntimeException { | |
100 processFile(fname, new Fetch() { | |
101 | |
102 public void readInto(ByteChannel ch) throws IOException, HgRuntimeException { | |
103 try { | |
104 ByteBuffer bb = ByteBuffer.wrap(new byte[8*1024]); | |
105 int r; | |
106 while ((r = content.read(bb.array())) != -1) { | |
107 bb.position(0).limit(r); | |
108 for (int wrote = 0; wrote < r; ) { | |
109 r -= wrote; | |
110 wrote = ch.write(bb); | |
111 assert bb.remaining() == r - wrote; | |
112 } | |
113 } | |
114 } catch (CancelledException ex) { | |
115 handleUnexpectedCancel(ex); | |
116 } | |
117 } | |
118 }, flags); | |
119 } | |
120 | |
121 private interface Fetch { | |
122 void readInto(ByteChannel ch) throws IOException, HgRuntimeException; | |
123 } | |
124 | |
125 private void processFile(Path fname, Fetch fetch, HgManifest.Flags flags) throws HgIOException, HgRuntimeException { | |
69 try { | 126 try { |
70 prepare(df.getPath()); | 127 byte[] symlinkContent = null; |
71 if (flags != HgManifest.Flags.Link) { | |
72 destChannel = new FileOutputStream(dest).getChannel(); | |
73 } else { | |
74 linkChannel = new ByteArrayChannel(); | |
75 } | |
76 df.contentWithFilters(fileRevIndex, this); | |
77 } catch (CancelledException ex) { | |
78 hgRepo.getSessionContext().getLog().dump(getClass(), Severity.Error, ex, "Our impl doesn't throw cancellation"); | |
79 } finally { | |
80 if (flags != HgManifest.Flags.Link) { | |
81 destChannel.close(); | |
82 destChannel = null; | |
83 // leave dest in case anyone enquires with #getDestinationFile | |
84 } | |
85 } | |
86 if (linkChannel != null && symlinkCap) { | |
87 assert flags == HgManifest.Flags.Link; | |
88 fileFlagsHelper.createSymlink(dest.getParentFile(), dest.getName(), linkChannel.toArray()); | |
89 } else if (flags == HgManifest.Flags.Exec && execCap) { | |
90 fileFlagsHelper.setExecutableBit(dest.getParentFile(), dest.getName()); | |
91 } | |
92 // Although HgWCStatusCollector treats 644 (`hg manifest -v`) and 664 (my fs) the same, it's better | |
93 // to detect actual flags here | |
94 fmode = flags.fsMode(); // default to one from manifest | |
95 if (fileFlagsHelper != null) { | |
96 // if neither execBit nor link is supported by fs, it's unlikely file mode is supported, too. | |
97 try { | 128 try { |
98 fmode = fileFlagsHelper.getFileMode(dest, fmode); | 129 prepare(fname, flags); |
99 } catch (IOException ex) { | 130 fetch.readInto(this); |
100 // Warn, we've got default value and can live with it | 131 } finally { |
101 hgRepo.getSessionContext().getLog().dump(getClass(), Warn, ex, "Failed get file access rights"); | 132 symlinkContent = close(fname, flags); |
102 } | 133 } |
103 } | 134 if (flags == HgManifest.Flags.Link && symlinkCap) { |
104 } | 135 assert symlinkContent != null; |
105 | 136 fileFlagsHelper.createSymlink(dest.getParentFile(), dest.getName(), symlinkContent); |
106 public void prepare(Path fname) throws IOException { | 137 } else if (flags == HgManifest.Flags.Exec && execCap) { |
138 fileFlagsHelper.setExecutableBit(dest.getParentFile(), dest.getName()); | |
139 } | |
140 // Although HgWCStatusCollector treats 644 (`hg manifest -v`) and 664 (my fs) the same, it's better | |
141 // to detect actual flags here | |
142 fmode = flags.fsMode(); // default to one from manifest | |
143 if (fileFlagsHelper != null) { | |
144 // if neither execBit nor link is supported by fs, it's unlikely file mode is supported, too. | |
145 try { | |
146 fmode = fileFlagsHelper.getFileMode(dest, fmode); | |
147 } catch (IOException ex) { | |
148 // Warn, we've got default value and can live with it | |
149 hgRepo.getSessionContext().getLog().dump(getClass(), Warn, ex, "Failed get file access rights"); | |
150 } | |
151 } | |
152 } catch (IOException ex) { | |
153 String msg = String.format("Failed to write file %s to the working directory", fname); | |
154 throw new HgIOException(msg, ex, dest); | |
155 } | |
156 } | |
157 | |
158 private void prepare(Path fname, HgManifest.Flags flags) throws IOException { | |
107 String fpath = fname.toString(); | 159 String fpath = fname.toString(); |
108 dest = new File(hgRepo.getRepo().getWorkingDir(), fpath); | 160 dest = new File(hgRepo.getRepo().getWorkingDir(), fpath); |
109 if (fpath.indexOf('/') != -1) { | 161 if (fpath.indexOf('/') != -1) { |
110 dest.getParentFile().mkdirs(); | 162 dest.getParentFile().mkdirs(); |
111 } | 163 } |
112 destChannel = null; | 164 destChannel = null; |
113 linkChannel = null; | 165 linkChannel = null; |
114 totalBytesWritten = 0; | 166 totalBytesWritten = 0; |
115 fmode = 0; | 167 fmode = 0; |
168 if (flags != HgManifest.Flags.Link) { | |
169 destChannel = new FileOutputStream(dest).getChannel(); | |
170 } else { | |
171 linkChannel = new ByteArrayChannel(); | |
172 } | |
173 } | |
174 | |
175 private byte[] close(Path fname, HgManifest.Flags flags) throws IOException { | |
176 if (flags != HgManifest.Flags.Link) { | |
177 destChannel.close(); | |
178 destChannel = null; | |
179 // leave dest in case anyone enquires with #getDestinationFile | |
180 } | |
181 if (linkChannel != null) { | |
182 final byte[] rv = linkChannel.toArray(); | |
183 linkChannel = null; | |
184 return rv; | |
185 } | |
186 return null; | |
116 } | 187 } |
117 | 188 |
118 public int write(ByteBuffer buffer) throws IOException, CancelledException { | 189 public int write(ByteBuffer buffer) throws IOException, CancelledException { |
119 final int written; | 190 final int written; |
120 if (linkChannel != null) { | 191 if (linkChannel != null) { |
142 } | 213 } |
143 | 214 |
144 public int mtime() { | 215 public int mtime() { |
145 return (int) (dest.lastModified() / 1000); | 216 return (int) (dest.lastModified() / 1000); |
146 } | 217 } |
218 | |
219 private void handleUnexpectedCancel(CancelledException ex) { | |
220 hgRepo.getSessionContext().getLog().dump(WorkingDirFileWriter.class, Severity.Error, ex, "Our impl doesn't throw cancellation"); | |
221 } | |
147 } | 222 } |