From 1c70dd6d219d2336b0d505739fe4c17677d5cc8c Mon Sep 17 00:00:00 2001 From: Shawn Pearce Date: Mon, 14 Nov 2016 11:00:34 -0800 Subject: [PATCH] Add {get,set}GitwebDescription to Repository This method pair allows the caller to read and modify the description file that is traditionally used by gitweb and cgit when rendering a repository on the web. Gerrit Code Review has offered this feature for years as part of its GitRepositoryManager interface, but its fundamentally a feature of JGit and its Repository abstraction. git-core typically initializes a repository with a default value inside the description file. During getDescription() this string is converted to null as it is never a useful description. Change-Id: I0a457026c74e9c73ea27e6f070d5fbaca3439be5 --- .../storage/file/DescriptionTest.java | 86 +++++++++++++++++++ .../eclipse/jgit/internal/JGitText.properties | 1 + .../org/eclipse/jgit/internal/JGitText.java | 1 + .../internal/storage/file/FileRepository.java | 64 ++++++++++++-- .../src/org/eclipse/jgit/lib/Repository.java | 28 +++++- 5 files changed, 174 insertions(+), 6 deletions(-) create mode 100644 org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java new file mode 100644 index 000000000..73bd35b19 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/DescriptionTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2016, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.internal.storage.file; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import java.io.File; +import java.io.IOException; + +import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; +import org.eclipse.jgit.lib.Repository; +import org.junit.Test; + +/** Test managing the gitweb description file. */ +public class DescriptionTest extends LocalDiskRepositoryTestCase { + private static final String UNCONFIGURED = "Unnamed repository; edit this file to name it for gitweb."; + + @Test + public void description() throws IOException { + Repository git = createBareRepository(); + File path = new File(git.getDirectory(), "description"); + assertNull("description", git.getGitwebDescription()); + + String desc = "a test repo\nfor jgit"; + git.setGitwebDescription(desc); + assertEquals(desc + '\n', read(path)); + assertEquals(desc, git.getGitwebDescription()); + + git.setGitwebDescription(null); + assertEquals("", read(path)); + + desc = "foo"; + git.setGitwebDescription(desc); + assertEquals(desc + '\n', read(path)); + assertEquals(desc, git.getGitwebDescription()); + + git.setGitwebDescription(""); + assertEquals("", read(path)); + + git.setGitwebDescription(UNCONFIGURED); + assertEquals(UNCONFIGURED + '\n', read(path)); + assertNull("description", git.getGitwebDescription()); + } +} diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index 0f2c8b3d1..8a16a3b19 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -675,6 +675,7 @@ unsupportedMark=Mark not supported unsupportedOperationNotAddAtEnd=Not add-at-end: {0} unsupportedPackIndexVersion=Unsupported pack index version {0} unsupportedPackVersion=Unsupported pack version {0}. +unsupportedRepositoryDescription=Repository description not supported updatingHeadFailed=Updating HEAD failed updatingReferences=Updating references updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 212cb7fde..3577c4b28 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -734,6 +734,7 @@ public class JGitText extends TranslationBundle { /***/ public String unsupportedOperationNotAddAtEnd; /***/ public String unsupportedPackIndexVersion; /***/ public String unsupportedPackVersion; + /***/ public String unsupportedRepositoryDescription; /***/ public String updatingHeadFailed; /***/ public String updatingReferences; /***/ public String updatingRefFailed; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java index 5b93399a7..ed1281bc6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java @@ -55,8 +55,10 @@ import java.io.IOException; import java.text.MessageFormat; import java.text.ParseException; import java.util.HashSet; +import java.util.Objects; import java.util.Set; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.attributes.AttributesNode; import org.eclipse.jgit.attributes.AttributesNodeProvider; @@ -85,6 +87,8 @@ import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.RawParseUtils; import org.eclipse.jgit.util.StringUtils; import org.eclipse.jgit.util.SystemReader; @@ -114,16 +118,13 @@ import org.eclipse.jgit.util.SystemReader; * */ public class FileRepository extends Repository { - private final FileBasedConfig systemConfig; + private static final String UNNAMED = "Unnamed repository; edit this file to name it for gitweb."; //$NON-NLS-1$ + private final FileBasedConfig systemConfig; private final FileBasedConfig userConfig; - private final FileBasedConfig repoConfig; - private final RefDatabase refs; - private final ObjectDirectory objectDatabase; - private FileSnapshot snapshot; /** @@ -420,6 +421,59 @@ public class FileRepository extends Repository { return repoConfig; } + @Override + @Nullable + public String getGitwebDescription() throws IOException { + String d; + try { + d = RawParseUtils.decode(IO.readFully(descriptionFile())); + } catch (FileNotFoundException err) { + return null; + } + if (d != null) { + d = d.trim(); + if (d.isEmpty() || UNNAMED.equals(d)) { + return null; + } + } + return d; + } + + @Override + public void setGitwebDescription(@Nullable String description) + throws IOException { + String old = getGitwebDescription(); + if (Objects.equals(old, description)) { + return; + } + + File path = descriptionFile(); + LockFile lock = new LockFile(path); + if (!lock.lock()) { + throw new IOException(MessageFormat.format(JGitText.get().lockError, + path.getAbsolutePath())); + } + try { + String d = description; + if (d != null) { + d = d.trim(); + if (!d.isEmpty()) { + d += '\n'; + } + } else { + d = ""; //$NON-NLS-1$ + } + lock.write(Constants.encode(d)); + lock.commit(); + } finally { + lock.unlock(); + } + } + + private File descriptionFile() { + return new File(getDirectory(), "description"); //$NON-NLS-1$ + } + /** * Objects known to exist but not expressed by {@link #getAllRefs()}. *

diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java index 1909037ee..19d9610d0 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java @@ -246,7 +246,6 @@ public abstract class Repository implements AutoCloseable { @NonNull public abstract AttributesNodeProvider createAttributesNodeProvider(); - /** * @return the used file system abstraction, or or {@code null} if * repository isn't local. @@ -1436,6 +1435,33 @@ public abstract class Repository implements AutoCloseable { return null; } + /** + * Read the {@code GIT_DIR/description} file for gitweb. + * + * @return description text; null if no description has been configured. + * @throws IOException + * description cannot be accessed. + * @since 4.6 + */ + @Nullable + public String getGitwebDescription() throws IOException { + return null; + } + + /** + * Set the {@code GIT_DIR/description} file for gitweb. + * + * @param description + * new description; null to clear the description. + * @throws IOException + * description cannot be persisted. + * @since 4.6 + */ + public void setGitwebDescription(@Nullable String description) + throws IOException { + throw new IOException(JGitText.get().unsupportedRepositoryDescription); + } + /** * @param refName * @return a {@link ReflogReader} for the supplied refname, or {@code null}