Browse Source

Allow ArchiveCommand.registerFormat to be called twice

This should make it possible for the gitiles plugin to register its
archive formats after gerrit has already registered them.

Signed-off-by: Jonathan Nieder <jrn@google.com>
Change-Id: Icb80a446e583961a7278b707d572d6fe456c372c
tags/v3.4.0.201405051725-m7
Jonathan Nieder 10 years ago
parent
commit
d5110c32f9

+ 0
- 1
org.eclipse.jgit.archive/src/org/eclipse/jgit/archive/ArchiveFormats.java View File

@@ -66,7 +66,6 @@ public class ArchiveFormats {
* Register all included archive formats so they can be used
* as arguments to the ArchiveCommand.setFormat() method.
*
* Should not be called twice without a call to stop() in between.
* Not thread-safe.
*/
public static void registerAll() {

+ 1
- 1
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties View File

@@ -12,7 +12,7 @@ anExceptionOccurredWhileTryingToAddTheIdOfHEAD=An exception occurred while tryin
anSSHSessionHasBeenAlreadyCreated=An SSH session has been already created
applyingCommit=Applying {0}
archiveFormatAlreadyAbsent=Archive format already absent: {0}
archiveFormatAlreadyRegistered=Archive format already registered: {0}
archiveFormatAlreadyRegistered=Archive format already registered with different implementation: {0}
argumentIsNotAValidCommentString=Invalid comment: {0}
atLeastOnePathIsRequired=At least one path is required.
atLeastOnePatternIsRequired=At least one pattern is required.

+ 90
- 20
org.eclipse.jgit/src/org/eclipse/jgit/api/ArchiveCommand.java View File

@@ -189,65 +189,135 @@ public class ArchiveCommand extends GitCommand<OutputStream> {
}
}

private static class FormatEntry {
final Format<?> format;
/** Number of times this format has been registered. */
final int refcnt;

public FormatEntry(Format<?> format, int refcnt) {
if (format == null)
throw new NullPointerException();
this.format = format;
this.refcnt = refcnt;
}
};

/**
* Available archival formats (corresponding to values for
* the --format= option)
*/
private static final ConcurrentMap<String, Format<?>> formats =
new ConcurrentHashMap<String, Format<?>>();
private static final ConcurrentMap<String, FormatEntry> formats =
new ConcurrentHashMap<String, FormatEntry>();

/**
* Replaces the entry for a key only if currently mapped to a given
* value.
*
* @param map a map
* @param key key with which the specified value is associated
* @param oldValue expected value for the key (null if should be absent).
* @param newValue value to be associated with the key (null to remove).
* @return true if the value was replaced
*/
private static <K, V> boolean replace(ConcurrentMap<K, V> map,
K key, V oldValue, V newValue) {
if (oldValue == null && newValue == null) // Nothing to do.
return true;

if (oldValue == null)
return map.putIfAbsent(key, newValue) == null;
else if (newValue == null)
return map.remove(key, oldValue);
else
return map.replace(key, oldValue, newValue);
}

/**
* Adds support for an additional archival format. To avoid
* unnecessary dependencies, ArchiveCommand does not have support
* for any formats built in; use this function to add them.
*
* <p>
* OSGi plugins providing formats should call this function at
* bundle activation time.
* <p>
* It is okay to register the same archive format with the same
* name multiple times, but don't forget to unregister it that
* same number of times, too.
* <p>
* Registering multiple formats with different names and the
* same or overlapping suffixes results in undefined behavior.
* TODO: check that suffixes don't overlap.
*
* @param name name of a format (e.g., "tar" or "zip").
* @param fmt archiver for that format
* @throws JGitInternalException
* An archival format with that name was already registered.
* A different archival format with that name was
* already registered.
*/
public static void registerFormat(String name, Format<?> fmt) {
// TODO(jrn): Check that suffixes don't overlap.

if (formats.putIfAbsent(name, fmt) != null)
throw new JGitInternalException(MessageFormat.format(
JGitText.get().archiveFormatAlreadyRegistered,
name));
if (fmt == null)
throw new NullPointerException();

FormatEntry old, entry;
do {
old = formats.get(name);
if (old == null) {
entry = new FormatEntry(fmt, 1);
continue;
}
if (!old.format.equals(fmt))
throw new JGitInternalException(MessageFormat.format(
JGitText.get().archiveFormatAlreadyRegistered,
name));
entry = new FormatEntry(old.format, old.refcnt + 1);
} while (!replace(formats, name, old, entry));
}

/**
* Removes support for an archival format so its Format can be
* garbage collected.
* Marks support for an archival format as no longer needed so its
* Format can be garbage collected if no one else is using it either.
* <p>
* In other words, this decrements the reference count for an
* archival format. If the reference count becomes zero, removes
* support for that format.
*
* @param name name of format (e.g., "tar" or "zip").
* @throws JGitInternalException
* No such archival format was registered.
*/
public static void unregisterFormat(String name) {
if (formats.remove(name) == null)
throw new JGitInternalException(MessageFormat.format(
JGitText.get().archiveFormatAlreadyAbsent,
name));
FormatEntry old, entry;
do {
old = formats.get(name);
if (old == null)
throw new JGitInternalException(MessageFormat.format(
JGitText.get().archiveFormatAlreadyAbsent,
name));
if (old.refcnt == 1) {
entry = null;
continue;
}
entry = new FormatEntry(old.format, old.refcnt - 1);
} while (!replace(formats, name, old, entry));
}

private static Format<?> formatBySuffix(String filenameSuffix)
throws UnsupportedFormatException {
if (filenameSuffix != null)
for (Format<?> fmt : formats.values())
for (FormatEntry entry : formats.values()) {
Format<?> fmt = entry.format;
for (String sfx : fmt.suffixes())
if (filenameSuffix.endsWith(sfx))
return fmt;
}
return lookupFormat("tar"); //$NON-NLS-1$
}

private static Format<?> lookupFormat(String formatName) throws UnsupportedFormatException {
Format<?> fmt = formats.get(formatName);
if (fmt == null)
FormatEntry entry = formats.get(formatName);
if (entry == null)
throw new UnsupportedFormatException(formatName);
return fmt;
return entry.format;
}

private OutputStream out;

Loading…
Cancel
Save