From d31e5586ad5e7b936ba7535e192c05653d82c7fe Mon Sep 17 00:00:00 2001 From: Edwin Kempin Date: Sat, 30 Nov 2013 12:07:08 +0100 Subject: [PATCH] Add REST endpoint to get content of a file from HEAD of a branch By GET on /projects//branches//files//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 --- Documentation/rest-api-projects.txt | 25 ++++++++++ .../gerrit/server/change/GetContent.java | 15 +++--- .../gerrit/server/project/FileResource.java | 35 ++++++++++++++ .../server/project/FilesCollection.java | 48 +++++++++++++++++++ .../gerrit/server/project/GetContent.java | 39 +++++++++++++++ .../google/gerrit/server/project/Module.java | 4 ++ 6 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java diff --git a/Documentation/rest-api-projects.txt b/Documentation/rest-api-projects.txt index c478e79fef..fed5b04222 100644 --- a/Documentation/rest-api-projects.txt +++ b/Documentation/rest-api-projects.txt @@ -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 ----------------------- diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java index c0e3d68a27..86a3da6f4a 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/GetContent.java @@ -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 { @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(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java new file mode 100644 index 0000000000..29506c9787 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FileResource.java @@ -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> FILE_KIND = + new TypeLiteral>() {}; + + private final String path; + + public FileResource(BranchResource rsrc, String path) { + super(rsrc.getControl(), rsrc.getBranchInfo()); + this.path = path; + } + + public String getPath() { + return path; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java new file mode 100644 index 0000000000..389189e648 --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/FilesCollection.java @@ -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 { + private final DynamicMap> views; + + @Inject + FilesCollection(DynamicMap> views) { + this.views = views; + } + + @Override + public RestView list() throws ResourceNotFoundException { + throw new ResourceNotFoundException(); + } + + @Override + public FileResource parse(BranchResource parent, IdString id) { + return new FileResource(parent, id.get()); + } + + @Override + public DynamicMap> views() { + return views; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java new file mode 100644 index 0000000000..48a3ced7ee --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/GetContent.java @@ -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 { + private final Provider getContent; + + @Inject + GetContent(Provider getContent) { + this.getContent = getContent; + } + + @Override + public BinaryResult apply(FileResource rsrc) + throws ResourceNotFoundException, IOException { + return getContent.get().apply(rsrc.getNameKey(), rsrc.getRef(), + rsrc.getPath()); + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/project/Module.java b/gerrit-server/src/main/java/com/google/gerrit/server/project/Module.java index 0ef875e77e..1b6c41052e 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/project/Module.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/project/Module.java @@ -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);