From 771f14b96e058649ca5db7ce6c99e38108d4abec Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer <contact@jacobvosmaer.nl>
Date: Tue, 2 Feb 2016 14:09:55 +0100
Subject: [PATCH] First version of "git archive" headers

---
 .../projects/repositories_controller.rb       |  4 ++-
 app/services/archive_repository_service.rb    | 23 ----------------
 lib/api/repositories.rb                       |  7 ++---
 lib/gitlab/workhorse.rb                       | 27 ++++++++++++++++---
 .../projects/repositories_controller_spec.rb  | 11 +++-----
 spec/lib/gitlab/workhorse_spec.rb             | 18 +++++++++++++
 .../archive_repository_service_spec.rb        | 25 -----------------
 7 files changed, 49 insertions(+), 66 deletions(-)
 delete mode 100644 app/services/archive_repository_service.rb
 create mode 100644 spec/lib/gitlab/workhorse_spec.rb
 delete mode 100644 spec/services/archive_repository_service_spec.rb

diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index ba9aea1c165..5c7614cfbaf 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -11,7 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
   end
 
   def archive
-    render json: ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
+    RepositoryArchiveCacheWorker.perform_async
+    headers.store(*Gitlab::Workhorse.send_git_archive(@project, params[:ref], params[:format]))
+    head :ok
   rescue => ex
     logger.error("#{self.class.name}: #{ex}")
     return git_not_found!
diff --git a/app/services/archive_repository_service.rb b/app/services/archive_repository_service.rb
deleted file mode 100644
index 2160bf13e6d..00000000000
--- a/app/services/archive_repository_service.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class ArchiveRepositoryService
-  attr_reader :project, :ref, :format
-
-  def initialize(project, ref, format)
-    format ||= 'tar.gz'
-    @project, @ref, @format = project, ref, format.downcase
-  end
-
-  def execute(options = {})
-    RepositoryArchiveCacheWorker.perform_async
-
-    metadata = project.repository.archive_metadata(ref, storage_path, format)
-    raise "Repository or ref not found" if metadata.empty?
-
-    metadata
-  end
-
-  private
-
-  def storage_path
-    Gitlab.config.gitlab.repository_downloads_path
-  end
-end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index c95d2d2001d..0178289f57f 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -98,11 +98,8 @@ module API
         authorize! :download_code, user_project
 
         begin
-          ArchiveRepositoryService.new(
-            user_project,
-            params[:sha],
-            params[:format]
-          ).execute
+          RepositoryArchiveCacheWorker.perform_async
+          header *Gitlab::Workhorse.send_git_archive(@project, params[:ref], params[:format])
         rescue
           not_found!('File')
         end
diff --git a/lib/gitlab/workhorse.rb b/lib/gitlab/workhorse.rb
index a23120a4176..2f3e57156b6 100644
--- a/lib/gitlab/workhorse.rb
+++ b/lib/gitlab/workhorse.rb
@@ -4,18 +4,37 @@ require 'json'
 module Gitlab
   class Workhorse
     class << self
+      SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data'
+
       def send_git_blob(repository, blob)
-        params_hash = {
+        params = {
           'RepoPath' => repository.path_to_repo,
           'BlobId' => blob.id,
         }
-        params = Base64.urlsafe_encode64(JSON.dump(params_hash))
 
         [
-          'Gitlab-Workhorse-Send-Data',
-          "git-blob:#{params}",
+          SEND_DATA_HEADER,
+          "git-blob:#{encode(params)}",
         ]
       end
+
+      def send_git_archive(project, ref, format)
+        format ||= 'tar.gz'
+        format.downcase!
+        params = project.repository.archive_metadata(ref, Gitlab.config.gitlab.repository_downloads_path, format)
+        raise "Repository or ref not found" if params.empty?
+
+        [
+          SEND_DATA_HEADER,
+          "git-archive:#{encode(params)}",
+        ]
+      end
+      
+      protected
+      
+      def encode(hash)
+        Base64.urlsafe_encode64(JSON.dump(hash))
+      end
     end
   end
 end
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
index 18a30033ed8..09ec4f18f9d 100644
--- a/spec/controllers/projects/repositories_controller_spec.rb
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -8,15 +8,10 @@ describe Projects::RepositoriesController do
     before do
       sign_in(user)
       project.team << [user, :developer]
-
-      allow(ArchiveRepositoryService).to receive(:new).and_return(service)
     end
 
-    let(:service) { ArchiveRepositoryService.new(project, "master", "zip") }
-
-    it "executes ArchiveRepositoryService" do
-      expect(ArchiveRepositoryService).to receive(:new).with(project, "master", "zip")
-      expect(service).to receive(:execute)
+    it "uses Gitlab::Workhorse" do
+      expect(Gitlab::Workhorse).to receive(:send_git_archive).with(project, "master", "zip")
 
       get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
     end
@@ -24,7 +19,7 @@ describe Projects::RepositoriesController do
     context "when the service raises an error" do
 
       before do
-        allow(service).to receive(:execute).and_raise("Archive failed")
+        allow(Gitlab::Workhorse).to receive(:send_git_archive).and_raise("Archive failed")
       end
 
       it "renders Not Found" do
diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb
new file mode 100644
index 00000000000..d940bf05061
--- /dev/null
+++ b/spec/lib/gitlab/workhorse_spec.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe Gitlab::Workhorse, lib: true do
+  let(:project) { create(:project) }
+  let(:subject) { Gitlab::Workhorse }
+
+  describe "#send_git_archive" do
+    context "when the repository doesn't have an archive file path" do
+      before do
+        allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
+      end
+
+      it "raises an error" do
+        expect { subject.send_git_archive(project, "master", "zip") }.to raise_error(RuntimeError)
+      end
+    end
+  end
+end
diff --git a/spec/services/archive_repository_service_spec.rb b/spec/services/archive_repository_service_spec.rb
deleted file mode 100644
index bd871605c66..00000000000
--- a/spec/services/archive_repository_service_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'spec_helper'
-
-describe ArchiveRepositoryService, services: true do
-  let(:project) { create(:project) }
-  subject { ArchiveRepositoryService.new(project, "master", "zip") }
-
-  describe "#execute" do
-    it "cleans old archives" do
-      expect(RepositoryArchiveCacheWorker).to receive(:perform_async)
-
-      subject.execute(timeout: 0.0)
-    end
-
-    context "when the repository doesn't have an archive file path" do
-      before do
-        allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
-      end
-
-      it "raises an error" do
-        expect { subject.execute(timeout: 0.0) }.to raise_error(RuntimeError)
-      end
-    end
-
-  end
-end
-- 
GitLab