Merge branch 'stable-3.0' into stable-3.1

* stable-3.0:
  ChangeEditModifier: Reject invalid file paths as '400 Bad Request'
  Remove orphan library downloader facility
  Fix a bug where _moreChanges is set to the wrong value
  Don't check conflicting ref names when deleting refs

Change-Id: Ic18373c4b4024de7bb9a50a8ac22651435e3b9cf
This commit is contained in:
David Pursehouse
2020-01-16 11:30:38 +09:00
10 changed files with 49 additions and 575 deletions

View File

@@ -150,6 +150,7 @@ public class RefUpdateUtil {
public static void deleteChecked(Repository repo, String refName) throws IOException { public static void deleteChecked(Repository repo, String refName) throws IOException {
RefUpdate ru = repo.updateRef(refName); RefUpdate ru = repo.updateRef(refName);
ru.setForceUpdate(true); ru.setForceUpdate(true);
ru.setCheckConflicting(false);
switch (ru.delete()) { switch (ru.delete()) {
case FORCED: case FORCED:
// Ref was deleted. // Ref was deleted.

View File

@@ -34,8 +34,6 @@ public class InitModule extends FactoryModule {
@Override @Override
protected void configure() { protected void configure() {
bind(SitePaths.class); bind(SitePaths.class);
bind(Libraries.class);
bind(LibraryDownloader.class);
factory(Section.Factory.class); factory(Section.Factory.class);
factory(VersionedAuthorizedKeysOnInit.Factory.class); factory(VersionedAuthorizedKeysOnInit.Factory.class);

View File

@@ -1,141 +0,0 @@
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.pgm.init;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.pgm.init.api.LibraryDownload;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.Config;
/** Standard {@link LibraryDownloader} instances derived from configuration. */
@Singleton
class Libraries {
private static final String RESOURCE_FILE = "com/google/gerrit/pgm/init/libraries.config";
private final Provider<LibraryDownloader> downloadProvider;
private final List<String> skippedDownloads;
private final boolean skipAllDownloads;
/* final */ LibraryDownloader db2Driver;
/* final */ LibraryDownloader db2DriverLicense;
/* final */ LibraryDownloader hanaDriver;
/* final */ LibraryDownloader mariadbDriver;
/* final */ LibraryDownloader mysqlDriver;
/* final */ LibraryDownloader oracleDriver;
@Inject
Libraries(
final Provider<LibraryDownloader> downloadProvider,
@LibraryDownload List<String> skippedDownloads,
@LibraryDownload Boolean skipAllDownloads) {
this.downloadProvider = downloadProvider;
this.skippedDownloads = skippedDownloads;
this.skipAllDownloads = skipAllDownloads;
init();
}
private void init() {
final Config cfg = new Config();
try {
cfg.fromText(read(RESOURCE_FILE));
} catch (IOException | ConfigInvalidException e) {
throw new RuntimeException(e.getMessage(), e);
}
for (Field f : Libraries.class.getDeclaredFields()) {
if ((f.getModifiers() & Modifier.STATIC) == 0 && f.getType() == LibraryDownloader.class) {
try {
f.set(this, downloadProvider.get());
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException("Cannot initialize " + f.getName());
}
}
}
for (Field f : Libraries.class.getDeclaredFields()) {
if ((f.getModifiers() & Modifier.STATIC) == 0 && f.getType() == LibraryDownloader.class) {
try {
init(f, cfg);
} catch (IllegalArgumentException
| IllegalAccessException
| NoSuchFieldException
| SecurityException e) {
throw new IllegalStateException("Cannot configure " + f.getName());
}
}
}
}
private void init(Field field, Config cfg)
throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
SecurityException {
String n = field.getName();
LibraryDownloader dl = (LibraryDownloader) field.get(this);
dl.setName(get(cfg, n, "name"));
dl.setJarUrl(get(cfg, n, "url"));
dl.setSHA1(getOptional(cfg, n, "sha1"));
dl.setRemove(get(cfg, n, "remove"));
for (String d : cfg.getStringList("library", n, "needs")) {
dl.addNeeds((LibraryDownloader) getClass().getDeclaredField(d).get(this));
}
dl.setSkipDownload(skipAllDownloads || skippedDownloads.contains(n));
}
private static String getOptional(Config cfg, String name, String key) {
return doGet(cfg, name, key, false);
}
private static String get(Config cfg, String name, String key) {
return doGet(cfg, name, key, true);
}
private static String doGet(Config cfg, String name, String key, boolean required) {
String val = cfg.getString("library", name, key);
if ((val == null || val.isEmpty()) && required) {
throw new IllegalStateException(
"Variable library." + name + "." + key + " is required within " + RESOURCE_FILE);
}
return val;
}
private static String read(String p) throws IOException {
try (InputStream in = Libraries.class.getClassLoader().getResourceAsStream(p)) {
if (in == null) {
throw new FileNotFoundException("Cannot load resource " + p);
}
try (Reader r = new InputStreamReader(in, UTF_8)) {
final StringBuilder buf = new StringBuilder();
final char[] tmp = new char[512];
int n;
while (0 < (n = r.read(tmp))) {
buf.append(tmp, 0, n);
}
return buf.toString();
}
}
}
}

View File

@@ -1,316 +0,0 @@
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.pgm.init;
import com.google.common.hash.Funnels;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.io.ByteStreams;
import com.google.gerrit.common.Die;
import com.google.gerrit.common.IoUtil;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jgit.util.HttpSupport;
/** Get optional or required 3rd party library files into $site_path/lib. */
class LibraryDownloader {
private final ConsoleUI ui;
private final Path lib_dir;
private final StaleLibraryRemover remover;
private boolean required;
private String name;
private String jarUrl;
private String sha1;
private String remove;
private List<LibraryDownloader> needs;
private LibraryDownloader neededBy;
private Path dst;
private boolean download; // download or copy
private boolean exists;
private boolean skipDownload;
@Inject
LibraryDownloader(ConsoleUI ui, SitePaths site, StaleLibraryRemover remover) {
this.ui = ui;
this.lib_dir = site.lib_dir;
this.remover = remover;
this.needs = new ArrayList<>(2);
}
void setName(String name) {
this.name = name;
}
void setJarUrl(String url) {
this.jarUrl = url;
download = jarUrl.startsWith("http");
}
void setSHA1(String sha1) {
this.sha1 = sha1;
}
void setRemove(String remove) {
this.remove = remove;
}
void addNeeds(LibraryDownloader lib) {
needs.add(lib);
}
void setSkipDownload(boolean skipDownload) {
this.skipDownload = skipDownload;
}
void downloadRequired() {
setRequired(true);
download();
}
void downloadOptional() {
required = false;
download();
}
private void setRequired(boolean r) {
required = r;
for (LibraryDownloader d : needs) {
d.setRequired(r);
}
}
private void download() {
if (skipDownload) {
return;
}
if (jarUrl == null || !jarUrl.contains("/")) {
throw new IllegalStateException("Invalid JarUrl for " + name);
}
final String jarName = jarUrl.substring(jarUrl.lastIndexOf('/') + 1);
if (jarName.contains("/") || jarName.contains("\\")) {
throw new IllegalStateException("Invalid JarUrl: " + jarUrl);
}
if (name == null) {
name = jarName;
}
dst = lib_dir.resolve(jarName);
if (Files.exists(dst)) {
exists = true;
} else if (shouldGet()) {
doGet();
}
if (exists) {
for (LibraryDownloader d : needs) {
d.neededBy = this;
d.downloadRequired();
}
}
}
private boolean shouldGet() {
if (ui.isBatch()) {
return required;
}
final StringBuilder msg = new StringBuilder();
msg.append("\n");
msg.append("Gerrit Code Review is not shipped with %s\n");
if (neededBy != null) {
msg.append(String.format("** This library is required by %s. **\n", neededBy.name));
} else if (required) {
msg.append("** This library is required for your configuration. **\n");
} else {
msg.append(" If available, Gerrit can take advantage of features\n");
msg.append(" in the library, but will also function without it.\n");
}
msg.append(String.format("%s and install it now", download ? "Download" : "Copy"));
return ui.yesno(true, msg.toString(), name);
}
private void doGet() {
if (!Files.exists(lib_dir)) {
try {
Files.createDirectories(lib_dir);
} catch (IOException e) {
throw new Die("Cannot create " + lib_dir, e);
}
}
try {
remover.remove(remove);
if (download) {
doGetByHttp();
} else {
doGetByLocalCopy();
}
verifyFileChecksum();
} catch (IOException err) {
try {
Files.delete(dst);
} catch (IOException e) {
// Delete failed; leave alone.
}
if (ui.isBatch()) {
throw new Die("error: Cannot get " + jarUrl, err);
}
System.err.println();
System.err.println();
System.err.println("error: " + err.getMessage());
System.err.println("Please download:");
System.err.println();
System.err.println(" " + jarUrl);
System.err.println();
System.err.println("and save as:");
System.err.println();
System.err.println(" " + dst.toAbsolutePath());
System.err.println();
System.err.flush();
ui.waitForUser();
if (Files.exists(dst)) {
verifyFileChecksum();
} else if (!ui.yesno(!required, "Continue without this library")) {
throw new Die("aborted by user");
}
}
if (Files.exists(dst)) {
exists = true;
IoUtil.loadJARs(dst);
}
}
private void doGetByLocalCopy() throws IOException {
System.err.print("Copying " + jarUrl + " ...");
Path p = url2file(jarUrl);
if (!Files.exists(p)) {
StringBuilder msg =
new StringBuilder()
.append("\n")
.append("Can not find the %s at this location: %s\n")
.append("Please provide alternative URL");
p = url2file(ui.readString(null, msg.toString(), name, jarUrl));
}
Files.copy(p, dst);
}
private static Path url2file(String urlString) throws IOException {
final URL url = new URL(urlString);
try {
return Paths.get(url.toURI());
} catch (URISyntaxException e) {
return Paths.get(url.getPath());
}
}
private void doGetByHttp() throws IOException {
System.err.print("Downloading " + jarUrl + " ...");
System.err.flush();
try (InputStream in = openHttpStream(jarUrl);
OutputStream out = Files.newOutputStream(dst)) {
ByteStreams.copy(in, out);
System.err.println(" OK");
System.err.flush();
} catch (IOException err) {
deleteDst();
System.err.println(" !! FAIL !!");
System.err.println(err);
System.err.flush();
throw err;
}
}
private static InputStream openHttpStream(String urlStr) throws IOException {
ProxySelector proxySelector = ProxySelector.getDefault();
URL url = new URL(urlStr);
Proxy proxy = HttpSupport.proxyFor(proxySelector, url);
HttpURLConnection c = (HttpURLConnection) url.openConnection(proxy);
switch (HttpSupport.response(c)) {
case HttpURLConnection.HTTP_OK:
return c.getInputStream();
case HttpURLConnection.HTTP_NOT_FOUND:
throw new FileNotFoundException(url.toString());
default:
throw new IOException(
url.toString() + ": " + HttpSupport.response(c) + " " + c.getResponseMessage());
}
}
@SuppressWarnings("deprecation") // Use Hashing.sha1 for compatibility.
private void verifyFileChecksum() {
if (sha1 == null) {
System.err.println();
System.err.flush();
return;
}
Hasher h = Hashing.sha1().newHasher();
try (InputStream in = Files.newInputStream(dst);
OutputStream out = Funnels.asOutputStream(h)) {
ByteStreams.copy(in, out);
} catch (IOException e) {
deleteDst();
throw new Die("cannot checksum " + dst, e);
}
if (sha1.equals(h.hash().toString())) {
System.err.println("Checksum " + dst.getFileName() + " OK");
System.err.flush();
} else if (ui.isBatch()) {
deleteDst();
throw new Die(dst + " SHA-1 checksum does not match");
} else if (!ui.yesno(
null /* force an answer */,
"error: SHA-1 checksum does not match\nUse %s anyway", //
dst.getFileName())) {
deleteDst();
throw new Die("aborted by user");
}
}
private void deleteDst() {
try {
Files.delete(dst);
} catch (IOException e) {
System.err.println(" Failed to clean up lib: " + dst);
}
}
}

View File

@@ -51,6 +51,7 @@ import java.sql.Timestamp;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.TimeZone; import java.util.TimeZone;
import org.eclipse.jgit.dircache.InvalidPathException;
import org.eclipse.jgit.lib.BatchRefUpdate; import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.CommitBuilder; import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.NullProgressMonitor;
@@ -243,13 +244,14 @@ public class ChangeEditModifier {
* @param filePath the path of the file whose contents should be modified * @param filePath the path of the file whose contents should be modified
* @param newContent the new file content * @param newContent the new file content
* @throws AuthException if the user isn't authenticated or not allowed to use change edits * @throws AuthException if the user isn't authenticated or not allowed to use change edits
* @throws BadRequestException if the user provided bad input (e.g. invalid file paths)
* @throws InvalidChangeOperationException if the file already had the specified content * @throws InvalidChangeOperationException if the file already had the specified content
* @throws PermissionBackendException * @throws PermissionBackendException
* @throws ResourceConflictException if the project state does not permit the operation * @throws ResourceConflictException if the project state does not permit the operation
*/ */
public void modifyFile( public void modifyFile(
Repository repository, ChangeNotes notes, String filePath, RawInput newContent) Repository repository, ChangeNotes notes, String filePath, RawInput newContent)
throws AuthException, InvalidChangeOperationException, IOException, throws AuthException, BadRequestException, InvalidChangeOperationException, IOException,
PermissionBackendException, ResourceConflictException { PermissionBackendException, ResourceConflictException {
modifyTree(repository, notes, new ChangeFileContentModification(filePath, newContent)); modifyTree(repository, notes, new ChangeFileContentModification(filePath, newContent));
} }
@@ -262,12 +264,13 @@ public class ChangeEditModifier {
* @param notes the {@link ChangeNotes} of the change whose change edit should be modified * @param notes the {@link ChangeNotes} of the change whose change edit should be modified
* @param file path of the file which should be deleted * @param file path of the file which should be deleted
* @throws AuthException if the user isn't authenticated or not allowed to use change edits * @throws AuthException if the user isn't authenticated or not allowed to use change edits
* @throws BadRequestException if the user provided bad input (e.g. invalid file paths)
* @throws InvalidChangeOperationException if the file does not exist * @throws InvalidChangeOperationException if the file does not exist
* @throws PermissionBackendException * @throws PermissionBackendException
* @throws ResourceConflictException if the project state does not permit the operation * @throws ResourceConflictException if the project state does not permit the operation
*/ */
public void deleteFile(Repository repository, ChangeNotes notes, String file) public void deleteFile(Repository repository, ChangeNotes notes, String file)
throws AuthException, InvalidChangeOperationException, IOException, throws AuthException, BadRequestException, InvalidChangeOperationException, IOException,
PermissionBackendException, ResourceConflictException { PermissionBackendException, ResourceConflictException {
modifyTree(repository, notes, new DeleteFileModification(file)); modifyTree(repository, notes, new DeleteFileModification(file));
} }
@@ -281,6 +284,7 @@ public class ChangeEditModifier {
* @param currentFilePath the current path/name of the file * @param currentFilePath the current path/name of the file
* @param newFilePath the desired path/name of the file * @param newFilePath the desired path/name of the file
* @throws AuthException if the user isn't authenticated or not allowed to use change edits * @throws AuthException if the user isn't authenticated or not allowed to use change edits
* @throws BadRequestException if the user provided bad input (e.g. invalid file paths)
* @throws InvalidChangeOperationException if the file was already renamed to the specified new * @throws InvalidChangeOperationException if the file was already renamed to the specified new
* name * name
* @throws PermissionBackendException * @throws PermissionBackendException
@@ -288,7 +292,7 @@ public class ChangeEditModifier {
*/ */
public void renameFile( public void renameFile(
Repository repository, ChangeNotes notes, String currentFilePath, String newFilePath) Repository repository, ChangeNotes notes, String currentFilePath, String newFilePath)
throws AuthException, InvalidChangeOperationException, IOException, throws AuthException, BadRequestException, InvalidChangeOperationException, IOException,
PermissionBackendException, ResourceConflictException { PermissionBackendException, ResourceConflictException {
modifyTree(repository, notes, new RenameFileModification(currentFilePath, newFilePath)); modifyTree(repository, notes, new RenameFileModification(currentFilePath, newFilePath));
} }
@@ -306,14 +310,14 @@ public class ChangeEditModifier {
* @throws PermissionBackendException * @throws PermissionBackendException
*/ */
public void restoreFile(Repository repository, ChangeNotes notes, String file) public void restoreFile(Repository repository, ChangeNotes notes, String file)
throws AuthException, InvalidChangeOperationException, IOException, throws AuthException, BadRequestException, InvalidChangeOperationException, IOException,
PermissionBackendException, ResourceConflictException { PermissionBackendException, ResourceConflictException {
modifyTree(repository, notes, new RestoreFileModification(file)); modifyTree(repository, notes, new RestoreFileModification(file));
} }
private void modifyTree( private void modifyTree(
Repository repository, ChangeNotes notes, TreeModification treeModification) Repository repository, ChangeNotes notes, TreeModification treeModification)
throws AuthException, IOException, InvalidChangeOperationException, throws AuthException, BadRequestException, IOException, InvalidChangeOperationException,
PermissionBackendException, ResourceConflictException { PermissionBackendException, ResourceConflictException {
assertCanEdit(notes); assertCanEdit(notes);
@@ -358,8 +362,8 @@ public class ChangeEditModifier {
ChangeNotes notes, ChangeNotes notes,
PatchSet patchSet, PatchSet patchSet,
List<TreeModification> treeModifications) List<TreeModification> treeModifications)
throws AuthException, IOException, InvalidChangeOperationException, MergeConflictException, throws AuthException, BadRequestException, IOException, InvalidChangeOperationException,
PermissionBackendException, ResourceConflictException { MergeConflictException, PermissionBackendException, ResourceConflictException {
assertCanEdit(notes); assertCanEdit(notes);
Optional<ChangeEdit> optionalChangeEdit = lookupChangeEdit(notes); Optional<ChangeEdit> optionalChangeEdit = lookupChangeEdit(notes);
@@ -469,10 +473,15 @@ public class ChangeEditModifier {
private static ObjectId createNewTree( private static ObjectId createNewTree(
Repository repository, RevCommit baseCommit, List<TreeModification> treeModifications) Repository repository, RevCommit baseCommit, List<TreeModification> treeModifications)
throws IOException, InvalidChangeOperationException { throws BadRequestException, IOException, InvalidChangeOperationException {
TreeCreator treeCreator = new TreeCreator(baseCommit); ObjectId newTreeId;
treeCreator.addTreeModifications(treeModifications); try {
ObjectId newTreeId = treeCreator.createNewTreeAndGetId(repository); TreeCreator treeCreator = new TreeCreator(baseCommit);
treeCreator.addTreeModifications(treeModifications);
newTreeId = treeCreator.createNewTreeAndGetId(repository);
} catch (InvalidPathException e) {
throw new BadRequestException(e.getMessage());
}
if (ObjectId.isEqual(newTreeId, baseCommit.getTree())) { if (ObjectId.isEqual(newTreeId, baseCommit.getTree())) {
throw new InvalidChangeOperationException("no changes were made"); throw new InvalidChangeOperationException("no changes were made");

View File

@@ -18,6 +18,7 @@ import com.google.gerrit.entities.PatchSet;
import com.google.gerrit.entities.Project; import com.google.gerrit.entities.Project;
import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response; import com.google.gerrit.extensions.restapi.Response;
@@ -65,8 +66,8 @@ public class ApplyFix implements RestModifyView<FixResource, Void> {
@Override @Override
public Response<EditInfo> apply(FixResource fixResource, Void nothing) public Response<EditInfo> apply(FixResource fixResource, Void nothing)
throws AuthException, ResourceConflictException, IOException, ResourceNotFoundException, throws AuthException, BadRequestException, ResourceConflictException, IOException,
PermissionBackendException { ResourceNotFoundException, PermissionBackendException {
RevisionResource revisionResource = fixResource.getRevisionResource(); RevisionResource revisionResource = fixResource.getRevisionResource();
Project.NameKey project = revisionResource.getProject(); Project.NameKey project = revisionResource.getProject();
ProjectState projectState = projectCache.checkedGet(project); ProjectState projectState = projectCache.checkedGet(project);

View File

@@ -118,7 +118,8 @@ public class ChangeEdits implements ChildCollection<ChangeResource, ChangeEditRe
@Override @Override
public Response<?> apply(ChangeResource resource, IdString id, Put.Input input) public Response<?> apply(ChangeResource resource, IdString id, Put.Input input)
throws AuthException, ResourceConflictException, IOException, PermissionBackendException { throws AuthException, ResourceConflictException, BadRequestException, IOException,
PermissionBackendException {
putEdit.apply(resource, id.get(), input.content); putEdit.apply(resource, id.get(), input.content);
return Response.none(); return Response.none();
} }
@@ -135,7 +136,8 @@ public class ChangeEdits implements ChildCollection<ChangeResource, ChangeEditRe
@Override @Override
public Response<?> apply(ChangeResource rsrc, IdString id, Input in) public Response<?> apply(ChangeResource rsrc, IdString id, Input in)
throws IOException, AuthException, ResourceConflictException, PermissionBackendException { throws IOException, AuthException, BadRequestException, ResourceConflictException,
PermissionBackendException {
return deleteContent.apply(rsrc, id.get()); return deleteContent.apply(rsrc, id.get());
} }
} }
@@ -236,7 +238,8 @@ public class ChangeEdits implements ChildCollection<ChangeResource, ChangeEditRe
@Override @Override
public Response<?> apply(ChangeResource resource, Post.Input input) public Response<?> apply(ChangeResource resource, Post.Input input)
throws AuthException, IOException, ResourceConflictException, PermissionBackendException { throws AuthException, BadRequestException, IOException, ResourceConflictException,
PermissionBackendException {
Project.NameKey project = resource.getProject(); Project.NameKey project = resource.getProject();
try (Repository repository = repositoryManager.openRepository(project)) { try (Repository repository = repositoryManager.openRepository(project)) {
if (isRestoreFile(input)) { if (isRestoreFile(input)) {
@@ -281,12 +284,14 @@ public class ChangeEdits implements ChildCollection<ChangeResource, ChangeEditRe
@Override @Override
public Response<?> apply(ChangeEditResource rsrc, Input input) public Response<?> apply(ChangeEditResource rsrc, Input input)
throws AuthException, ResourceConflictException, IOException, PermissionBackendException { throws AuthException, ResourceConflictException, BadRequestException, IOException,
PermissionBackendException {
return apply(rsrc.getChangeResource(), rsrc.getPath(), input.content); return apply(rsrc.getChangeResource(), rsrc.getPath(), input.content);
} }
public Response<?> apply(ChangeResource rsrc, String path, RawInput newContent) public Response<?> apply(ChangeResource rsrc, String path, RawInput newContent)
throws ResourceConflictException, AuthException, IOException, PermissionBackendException { throws ResourceConflictException, AuthException, BadRequestException, IOException,
PermissionBackendException {
if (Strings.isNullOrEmpty(path) || path.charAt(0) == '/') { if (Strings.isNullOrEmpty(path) || path.charAt(0) == '/') {
throw new ResourceConflictException("Invalid path: " + path); throw new ResourceConflictException("Invalid path: " + path);
} }
@@ -320,12 +325,14 @@ public class ChangeEdits implements ChildCollection<ChangeResource, ChangeEditRe
@Override @Override
public Response<?> apply(ChangeEditResource rsrc, Input input) public Response<?> apply(ChangeEditResource rsrc, Input input)
throws AuthException, ResourceConflictException, IOException, PermissionBackendException { throws AuthException, BadRequestException, ResourceConflictException, IOException,
PermissionBackendException {
return apply(rsrc.getChangeResource(), rsrc.getPath()); return apply(rsrc.getChangeResource(), rsrc.getPath());
} }
public Response<?> apply(ChangeResource rsrc, String filePath) public Response<?> apply(ChangeResource rsrc, String filePath)
throws AuthException, IOException, ResourceConflictException, PermissionBackendException { throws AuthException, BadRequestException, IOException, ResourceConflictException,
PermissionBackendException {
try (Repository repository = repositoryManager.openRepository(rsrc.getProject())) { try (Repository repository = repositoryManager.openRepository(rsrc.getProject())) {
editModifier.deleteFile(repository, rsrc.getNotes(), filePath); editModifier.deleteFile(repository, rsrc.getNotes(), filePath);
} catch (InvalidChangeOperationException e) { } catch (InvalidChangeOperationException e) {

View File

@@ -58,6 +58,7 @@ import com.google.gerrit.extensions.common.DiffInfo;
import com.google.gerrit.extensions.common.EditInfo; import com.google.gerrit.extensions.common.EditInfo;
import com.google.gerrit.extensions.common.FileInfo; import com.google.gerrit.extensions.common.FileInfo;
import com.google.gerrit.extensions.restapi.AuthException; import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.BinaryResult; import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceConflictException; import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.server.ChangeMessagesUtil; import com.google.gerrit.server.ChangeMessagesUtil;
@@ -435,6 +436,16 @@ public class ChangeEditIT extends AbstractDaemonTest {
assertThat(getFileContentOfEdit(changeId, FILE_NAME)).isAbsent(); assertThat(getFileContentOfEdit(changeId, FILE_NAME)).isAbsent();
} }
@Test
public void renameExistingFileToInvalidPath() throws Exception {
createEmptyEditFor(changeId);
BadRequestException badRequest =
assertThrows(
BadRequestException.class,
() -> gApi.changes().id(changeId).edit().renameFile(FILE_NAME, "invalid/path/"));
assertThat(badRequest.getMessage()).isEqualTo("Invalid path: invalid/path/");
}
@Test @Test
public void createEditByDeletingExistingFileRest() throws Exception { public void createEditByDeletingExistingFileRest() throws Exception {
adminRestSession.delete(urlEditFile(changeId, FILE_NAME)).assertNoContent(); adminRestSession.delete(urlEditFile(changeId, FILE_NAME)).assertNoContent();

View File

@@ -1,46 +0,0 @@
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.pgm.init;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.verifyZeroInteractions;
import com.google.gerrit.pgm.init.api.ConsoleUI;
import com.google.gerrit.server.config.SitePaths;
import java.nio.file.Paths;
import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
@RunWith(MockitoJUnitRunner.class)
public class LibrariesTest {
@Mock ConsoleUI ui;
@Mock StaleLibraryRemover remover;
@Test
public void create() throws Exception {
final SitePaths site = new SitePaths(Paths.get("."));
Libraries lib =
new Libraries(
() -> new LibraryDownloader(ui, site, remover), Collections.emptyList(), false);
assertNotNull(lib.mysqlDriver);
verifyZeroInteractions(ui);
verifyZeroInteractions(remover);
}
}

View File

@@ -1,50 +0,0 @@
# Copyright (C) 2009 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
[library "mysqlDriver"]
name = MySQL Connector/J 5.1.43
url = https://repo1.maven.org/maven2/mysql/mysql-connector-java/5.1.43/mysql-connector-java-5.1.43.jar
sha1 = dee9103eec0d877f3a21c82d4d9e9f4fbd2d6e0a
remove = mysql-connector-java-.*[.]jar
[library "mariadbDriver"]
name = MariaDB Connector/J 2.3.0
url = https://repo1.maven.org/maven2/org/mariadb/jdbc/mariadb-java-client/2.3.0/mariadb-java-client-2.3.0.jar
sha1 = c2b1a6002a169757d0649449288e9b3b776af76b
remove = mariadb-java-client-.*[.]jar
[library "oracleDriver"]
name = Oracle JDBC driver 11g Release 2 (11.2.0)
url = file:///u01/app/oracle/product/11.2.0/xe/jdbc/lib/ojdbc6.jar
sha1 = 2f89cd9176772c3a6c261ce6a8e3d0d4425f5679
remove = ojdbc6.jar
[library "db2Driver"]
name = DB2 Type 4 JDBC driver (10.5)
url = file:///opt/ibm/db2/V10.5/java/db2jcc4.jar
sha1 = 9344d4fd41d6511f2d1d1deb7759056495b3a39b
needs = db2DriverLicense
remove = db2jcc4.jar
# Omit SHA-1 for license JAR as it's not stable and depends on the product
# the customer has purchased.
[library "db2DriverLicense"]
name = DB2 Type 4 JDBC driver license (10.5)
url = file:///opt/ibm/db2/V10.5/java/db2jcc_license_cu.jar
remove = db2jcc_license_cu.jar
[library "hanaDriver"]
name = HANA JDBC driver
url = file:///usr/sap/hdbclient/ngdbc.jar
remove = ngdbc.jar