comparison src/org/tmatesoft/hg/internal/ChangelogEntryBuilder.java @ 618:7c0d2ce340b8

Refactor approach how content finds it way down to a commit revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Thu, 16 May 2013 19:46:13 +0200
parents dd4f6311af52
children 4e6179bde4fc
comparison
equal deleted inserted replaced
617:65c01508f002 618:7c0d2ce340b8
1 /* 1 /*
2 * Copyright (c) 2012 TMate Software Ltd 2 * Copyright (c) 2012-2013 TMate Software Ltd
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by 5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License. 6 * the Free Software Foundation; version 2 of the License.
7 * 7 *
14 * the terms of a license other than GNU General Public License 14 * the terms of a license other than GNU General Public License
15 * contact TMate Software at support@hg4j.com 15 * contact TMate Software at support@hg4j.com
16 */ 16 */
17 package org.tmatesoft.hg.internal; 17 package org.tmatesoft.hg.internal;
18 18
19 import java.io.ByteArrayOutputStream;
19 import java.util.ArrayList; 20 import java.util.ArrayList;
20 import java.util.Collection; 21 import java.util.Collection;
21 import java.util.Collections; 22 import java.util.Collections;
22 import java.util.Iterator; 23 import java.util.Iterator;
23 import java.util.LinkedHashMap; 24 import java.util.LinkedHashMap;
24 import java.util.List; 25 import java.util.List;
25 import java.util.Map; 26 import java.util.Map;
27 import java.util.Map.Entry;
26 import java.util.TimeZone; 28 import java.util.TimeZone;
27 import java.util.Map.Entry;
28 29
30 import org.tmatesoft.hg.core.HgIOException;
29 import org.tmatesoft.hg.core.Nodeid; 31 import org.tmatesoft.hg.core.Nodeid;
32 import org.tmatesoft.hg.internal.DataSerializer.DataSource;
30 import org.tmatesoft.hg.util.Path; 33 import org.tmatesoft.hg.util.Path;
31 34
32 /** 35 /**
33 * 36 * Builds changelog entry
34 * @author Artem Tikhomirov 37 * @author Artem Tikhomirov
35 * @author TMate Software Ltd. 38 * @author TMate Software Ltd.
36 */ 39 */
37 public class ChangelogEntryBuilder { 40 public class ChangelogEntryBuilder implements DataSource {
38 41
39 private String user; 42 private String user;
40 private List<Path> modifiedFiles; 43 private List<Path> modifiedFiles;
41 private final Map<String, String> extrasMap = new LinkedHashMap<String, String>(); 44 private final Map<String, String> extrasMap = new LinkedHashMap<String, String>();
42 private Integer tzOffset; 45 private Integer tzOffset;
43 private Long csetTime; 46 private Long csetTime;
47 private Nodeid manifestRev;
48 private CharSequence comment;
44 49
45 public ChangelogEntryBuilder user(String username) { 50 public ChangelogEntryBuilder user(String username) {
46 user = username; 51 user = username;
47 return this; 52 return this;
48 } 53 }
87 csetTime = seconds; 92 csetTime = seconds;
88 tzOffset = timezoneOffset; 93 tzOffset = timezoneOffset;
89 return this; 94 return this;
90 } 95 }
91 96
97 public ChangelogEntryBuilder manifest(Nodeid manifestRevision) {
98 manifestRev = manifestRevision;
99 return this;
100 }
101
102 public ChangelogEntryBuilder comment(CharSequence commentString) {
103 comment = commentString;
104 return this;
105 }
106
107 public void serialize(DataSerializer out) throws HgIOException {
108 byte[] b = build();
109 out.write(b, 0, b.length);
110 }
111
112 public int serializeLength() {
113 return -1;
114 }
115
116 public byte[] build() {
117 ByteArrayOutputStream out = new ByteArrayOutputStream();
118 final int LF = '\n';
119 CharSequence extras = buildExtras();
120 CharSequence files = buildFiles();
121 byte[] manifestRevision = manifestRev.toString().getBytes();
122 byte[] username = user().getBytes(EncodingHelper.getUTF8());
123 out.write(manifestRevision, 0, manifestRevision.length);
124 out.write(LF);
125 out.write(username, 0, username.length);
126 out.write(LF);
127 final long csetDate = csetTime();
128 byte[] date = String.format("%d %d", csetDate, csetTimezone(csetDate)).getBytes();
129 out.write(date, 0, date.length);
130 if (extras.length() > 0) {
131 out.write(' ');
132 byte[] b = extras.toString().getBytes();
133 out.write(b, 0, b.length);
134 }
135 out.write(LF);
136 byte[] b = files.toString().getBytes();
137 out.write(b, 0, b.length);
138 out.write(LF);
139 out.write(LF);
140 byte[] cmt = comment.toString().getBytes(EncodingHelper.getUTF8());
141 out.write(cmt, 0, cmt.length);
142 return out.toByteArray();
143 }
144
145 private CharSequence buildExtras() {
146 StringBuilder extras = new StringBuilder();
147 for (Iterator<Entry<String, String>> it = extrasMap.entrySet().iterator(); it.hasNext();) {
148 final Entry<String, String> next = it.next();
149 extras.append(encodeExtrasPair(next.getKey()));
150 extras.append(':');
151 extras.append(encodeExtrasPair(next.getValue()));
152 if (it.hasNext()) {
153 extras.append('\00');
154 }
155 }
156 return extras;
157 }
158
159 private CharSequence buildFiles() {
160 StringBuilder files = new StringBuilder();
161 if (modifiedFiles != null) {
162 Collections.sort(modifiedFiles);
163 for (Iterator<Path> it = modifiedFiles.iterator(); it.hasNext(); ) {
164 files.append(it.next());
165 if (it.hasNext()) {
166 files.append('\n');
167 }
168 }
169 }
170 return files;
171 }
172
173 private final static CharSequence encodeExtrasPair(String s) {
174 if (s != null) {
175 return s.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r").replace("\00", "\\0");
176 }
177 return s;
178 }
179
92 private long csetTime() { 180 private long csetTime() {
93 if (csetTime != null) { 181 if (csetTime != null) {
94 return csetTime; 182 return csetTime;
95 } 183 }
96 return System.currentTimeMillis() / 1000; 184 return System.currentTimeMillis() / 1000;
100 if (tzOffset != null) { 188 if (tzOffset != null) {
101 return tzOffset; 189 return tzOffset;
102 } 190 }
103 return -(TimeZone.getDefault().getOffset(time) / 1000); 191 return -(TimeZone.getDefault().getOffset(time) / 1000);
104 } 192 }
105
106 public byte[] build(Nodeid manifestRevision, String comment) {
107 String f = "%s\n%s\n%d %d %s\n%s\n\n%s";
108 StringBuilder extras = new StringBuilder();
109 for (Iterator<Entry<String, String>> it = extrasMap.entrySet().iterator(); it.hasNext();) {
110 final Entry<String, String> next = it.next();
111 extras.append(encodeExtrasPair(next.getKey()));
112 extras.append(':');
113 extras.append(encodeExtrasPair(next.getValue()));
114 if (it.hasNext()) {
115 extras.append('\00');
116 }
117 }
118 StringBuilder files = new StringBuilder();
119 if (modifiedFiles != null) {
120 for (Iterator<Path> it = modifiedFiles.iterator(); it.hasNext(); ) {
121 files.append(it.next());
122 if (it.hasNext()) {
123 files.append('\n');
124 }
125 }
126 }
127 final long date = csetTime();
128 final int tz = csetTimezone(date);
129 return String.format(f, manifestRevision.toString(), user(), date, tz, extras, files, comment).getBytes();
130 }
131
132 private final static CharSequence encodeExtrasPair(String s) {
133 if (s != null) {
134 return s.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r").replace("\00", "\\0");
135 }
136 return s;
137 }
138 } 193 }