Add REST endpoint to get content of a file from HEAD of a branch

By GET on /projects/<project-name>/branches/<branch>/files/<file>/content
it is now possible to retrieve the content of a file from the HEAD
revision of a certain branch. The file content is returned as base64
encoded string.

This endpoint is useful for integrating tools that need access to
certain files, e.g. a tool may need to get the pom.xml from every
project. In this case it would be too much overhead to clone each
repository just to get this one file from it.

Change-Id: I70f294fbcc8a4cc88cd3c1265653cc9870b6433e
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin
2013-11-30 12:07:08 +01:00
parent 8ba03ff10b
commit d31e5586ad
6 changed files with 160 additions and 6 deletions

View File

@@ -742,6 +742,31 @@ Deletes a branch.
HTTP/1.1 204 No Content
----
[[get-content]]
Get Content
~~~~~~~~~~~
--
'GET /projects/link:#project-name[\{project-name\}]/branches/link:#branch-id[\{branch-id\}]/files/link:rest-api-changes.html#file-id[\{file-id\}]/content'
--
Gets the content of a file from the HEAD revision of a certain branch.
.Request
----
GET /projects/gerrit/branches/master/files/gerrit-server%2Fsrc%2Fmain%2Fjava%2Fcom%2Fgoogle%2Fgerrit%2Fserver%2Fproject%2FRefControl.java/content HTTP/1.0
----
The content is returned as base64 encoded string.
.Response
----
HTTP/1.1 200 OK
Content-Disposition: attachment
Content-Type: text/plain;charset=UTF-8
Ly8gQ29weXJpZ2h0IChDKSAyMDEwIFRoZSBBbmRyb2lkIE9wZW4gU291cmNlIFByb2plY...
----
[[child-project-endpoints]]
Child Project Endpoints
-----------------------

View File

@@ -21,7 +21,6 @@ import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectLoader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
@@ -42,17 +41,21 @@ public class GetContent implements RestReadView<FileResource> {
@Override
public BinaryResult apply(FileResource rsrc)
throws ResourceNotFoundException, IOException {
Project.NameKey project =
rsrc.getRevision().getControl().getProject().getNameKey();
return apply(rsrc.getRevision().getControl().getProject().getNameKey(),
rsrc.getRevision().getPatchSet().getRevision().get(),
rsrc.getPatchKey().get());
}
public BinaryResult apply(Project.NameKey project, String revstr, String path)
throws ResourceNotFoundException, IOException {
Repository repo = repoManager.openRepository(project);
try {
RevWalk rw = new RevWalk(repo);
try {
RevCommit commit =
rw.parseCommit(ObjectId.fromString(rsrc.getRevision().getPatchSet()
.getRevision().get()));
rw.parseCommit(repo.resolve(revstr));
TreeWalk tw =
TreeWalk.forPath(rw.getObjectReader(), rsrc.getPatchKey().get(),
TreeWalk.forPath(rw.getObjectReader(), path,
commit.getTree().getId());
if (tw == null) {
throw new ResourceNotFoundException();

View File

@@ -0,0 +1,35 @@
// Copyright (C) 2013 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.server.project;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.project.BranchResource;
import com.google.inject.TypeLiteral;
public class FileResource extends BranchResource {
public static final TypeLiteral<RestView<FileResource>> FILE_KIND =
new TypeLiteral<RestView<FileResource>>() {};
private final String path;
public FileResource(BranchResource rsrc, String path) {
super(rsrc.getControl(), rsrc.getBranchInfo());
this.path = path;
}
public String getPath() {
return path;
}
}

View File

@@ -0,0 +1,48 @@
// Copyright (C) 2013 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.server.project;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.ChildCollection;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestView;
import com.google.gerrit.server.project.BranchResource;
import com.google.inject.Inject;
public class FilesCollection implements
ChildCollection<BranchResource, FileResource> {
private final DynamicMap<RestView<FileResource>> views;
@Inject
FilesCollection(DynamicMap<RestView<FileResource>> views) {
this.views = views;
}
@Override
public RestView<BranchResource> list() throws ResourceNotFoundException {
throw new ResourceNotFoundException();
}
@Override
public FileResource parse(BranchResource parent, IdString id) {
return new FileResource(parent, id.get());
}
@Override
public DynamicMap<RestView<FileResource>> views() {
return views;
}
}

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2013 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.server.project;
import com.google.gerrit.extensions.restapi.BinaryResult;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.io.IOException;
public class GetContent implements RestReadView<FileResource> {
private final Provider<com.google.gerrit.server.change.GetContent> getContent;
@Inject
GetContent(Provider<com.google.gerrit.server.change.GetContent> getContent) {
this.getContent = getContent;
}
@Override
public BinaryResult apply(FileResource rsrc)
throws ResourceNotFoundException, IOException {
return getContent.get().apply(rsrc.getNameKey(), rsrc.getRef(),
rsrc.getPath());
}
}

View File

@@ -18,6 +18,7 @@ import static com.google.gerrit.server.project.BranchResource.BRANCH_KIND;
import static com.google.gerrit.server.project.ChildProjectResource.CHILD_PROJECT_KIND;
import static com.google.gerrit.server.project.DashboardResource.DASHBOARD_KIND;
import static com.google.gerrit.server.project.ProjectResource.PROJECT_KIND;
import static com.google.gerrit.server.project.FileResource.FILE_KIND;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.RestApiModule;
@@ -33,6 +34,7 @@ public class Module extends RestApiModule {
DynamicMap.mapOf(binder(), CHILD_PROJECT_KIND);
DynamicMap.mapOf(binder(), BRANCH_KIND);
DynamicMap.mapOf(binder(), DASHBOARD_KIND);
DynamicMap.mapOf(binder(), FILE_KIND);
put(PROJECT_KIND).to(PutProject.class);
get(PROJECT_KIND).to(GetProject.class);
@@ -57,6 +59,8 @@ public class Module extends RestApiModule {
get(BRANCH_KIND).to(GetBranch.class);
delete(BRANCH_KIND).to(DeleteBranch.class);
install(new FactoryModuleBuilder().build(CreateBranch.Factory.class));
child(BRANCH_KIND, "files").to(FilesCollection.class);
get(FILE_KIND, "content").to(GetContent.class);
child(PROJECT_KIND, "dashboards").to(DashboardsCollection.class);
get(DASHBOARD_KIND).to(GetDashboard.class);