tikhomirov@384: /* tikhomirov@384: * Copyright (c) 2012 TMate Software Ltd tikhomirov@384: * tikhomirov@384: * This program is free software; you can redistribute it and/or modify tikhomirov@384: * it under the terms of the GNU General Public License as published by tikhomirov@384: * the Free Software Foundation; version 2 of the License. tikhomirov@384: * tikhomirov@384: * This program is distributed in the hope that it will be useful, tikhomirov@384: * but WITHOUT ANY WARRANTY; without even the implied warranty of tikhomirov@384: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the tikhomirov@384: * GNU General Public License for more details. tikhomirov@384: * tikhomirov@384: * For information on how to redistribute this software under tikhomirov@384: * the terms of a license other than GNU General Public License tikhomirov@384: * contact TMate Software at support@hg4j.com tikhomirov@384: */ tikhomirov@384: package org.tmatesoft.hg.tools; tikhomirov@384: tikhomirov@384: import java.util.ArrayList; tikhomirov@384: import java.util.Collections; tikhomirov@384: import java.util.Iterator; tikhomirov@384: import java.util.LinkedHashMap; tikhomirov@384: import java.util.List; tikhomirov@384: import java.util.Map; tikhomirov@384: import java.util.TimeZone; tikhomirov@384: import java.util.Map.Entry; tikhomirov@384: tikhomirov@384: import org.tmatesoft.hg.core.Nodeid; tikhomirov@384: tikhomirov@384: /** tikhomirov@384: * tikhomirov@384: * @author Artem Tikhomirov tikhomirov@384: * @author TMate Software Ltd. tikhomirov@384: */ tikhomirov@384: public class ChangelogEntryBuilder { tikhomirov@384: tikhomirov@384: private String user; tikhomirov@384: private List modifiedFiles; tikhomirov@384: private final Map extrasMap = new LinkedHashMap(); tikhomirov@384: private Integer tzOffset; tikhomirov@384: private Long csetTime; tikhomirov@384: tikhomirov@384: public ChangelogEntryBuilder user(String username) { tikhomirov@384: user = username; tikhomirov@384: return this; tikhomirov@384: } tikhomirov@384: tikhomirov@384: public String user() { tikhomirov@384: if (user == null) { tikhomirov@384: // for our testing purposes anything but null is ok. no reason to follow Hg username lookup conventions tikhomirov@384: user = System.getProperty("user.name"); tikhomirov@384: } tikhomirov@384: return user; tikhomirov@384: } tikhomirov@384: tikhomirov@384: public ChangelogEntryBuilder setModified(List files) { tikhomirov@384: modifiedFiles = new ArrayList(files == null ? Collections.emptyList() : files); tikhomirov@384: return this; tikhomirov@384: } tikhomirov@384: tikhomirov@384: public ChangelogEntryBuilder addModified(List files) { tikhomirov@384: if (modifiedFiles == null) { tikhomirov@384: return setModified(files); tikhomirov@384: } tikhomirov@384: modifiedFiles.addAll(files); tikhomirov@384: return this; tikhomirov@384: } tikhomirov@384: tikhomirov@384: public ChangelogEntryBuilder branch(String branchName) { tikhomirov@386: if (branchName == null || "default".equals(branchName)) { tikhomirov@384: extrasMap.remove("branch"); tikhomirov@384: } else { tikhomirov@384: extrasMap.put("branch", branchName); tikhomirov@384: } tikhomirov@384: return this; tikhomirov@384: } tikhomirov@384: tikhomirov@384: public ChangelogEntryBuilder extras(Map extras) { tikhomirov@384: extrasMap.clear(); tikhomirov@384: extrasMap.putAll(extras); tikhomirov@384: return this; tikhomirov@384: } tikhomirov@384: tikhomirov@384: public ChangelogEntryBuilder date(long seconds, int timezoneOffset) { tikhomirov@384: csetTime = seconds; tikhomirov@384: tzOffset = timezoneOffset; tikhomirov@384: return this; tikhomirov@384: } tikhomirov@384: tikhomirov@384: private long csetTime() { tikhomirov@384: if (csetTime != null) { tikhomirov@384: return csetTime; tikhomirov@384: } tikhomirov@384: return System.currentTimeMillis() / 1000; tikhomirov@384: } tikhomirov@384: tikhomirov@384: private int csetTimezone(long time) { tikhomirov@384: if (tzOffset != null) { tikhomirov@384: return tzOffset; tikhomirov@384: } tikhomirov@384: return -(TimeZone.getDefault().getOffset(time) / 1000); tikhomirov@384: } tikhomirov@384: tikhomirov@384: public byte[] build(Nodeid manifestRevision, String comment) { tikhomirov@384: String f = "%s\n%s\n%d %d %s\n%s\n\n%s"; tikhomirov@384: StringBuilder extras = new StringBuilder(); tikhomirov@384: for (Iterator> it = extrasMap.entrySet().iterator(); it.hasNext();) { tikhomirov@384: final Entry next = it.next(); tikhomirov@384: extras.append(encodeExtrasPair(next.getKey())); tikhomirov@384: extras.append(':'); tikhomirov@384: extras.append(encodeExtrasPair(next.getValue())); tikhomirov@384: if (it.hasNext()) { tikhomirov@384: extras.append('\00'); tikhomirov@384: } tikhomirov@384: } tikhomirov@384: StringBuilder files = new StringBuilder(); tikhomirov@386: if (modifiedFiles != null) { tikhomirov@386: for (Iterator it = modifiedFiles.iterator(); it.hasNext(); ) { tikhomirov@386: files.append(it.next()); tikhomirov@386: if (it.hasNext()) { tikhomirov@386: files.append('\n'); tikhomirov@386: } tikhomirov@384: } tikhomirov@384: } tikhomirov@384: final long date = csetTime(); tikhomirov@384: final int tz = csetTimezone(date); tikhomirov@386: return String.format(f, manifestRevision.toString(), user(), date, tz, extras, files, comment).getBytes(); tikhomirov@384: } tikhomirov@384: tikhomirov@384: private final static CharSequence encodeExtrasPair(String s) { tikhomirov@384: if (s != null) { tikhomirov@384: return s.replace("\\", "\\\\").replace("\n", "\\n").replace("\r", "\\r").replace("\00", "\\0"); tikhomirov@384: } tikhomirov@384: return s; tikhomirov@384: } tikhomirov@384: }