Read about our upcoming Code of Conduct on this issue

Commit 605c699f authored by Georges Racinet's avatar Georges Racinet 🦑
Browse files

Gitlab::Mercurial adopted method for repo creation

The main advantage is that this looks more uniform from the
upper layers, at the price of making
`Git::Repository.create_repository` accept arbitrary
arguments.

Also `Gitlab::Shell` is slowly being faded away. By
calling the raw repo's `create_repository` we are
actually anticipating on later versions.

The saner structure can be also be felt in that we
don't need to give some methods a classmethod
version any more.

--HG--
branch : heptapod
parent d84419257eb5
......@@ -1387,26 +1387,11 @@ def namespace_fs_pathname
Pathname('').join(*namespace.full_path.split('/'))
end
def create_repository(force: false)
return false unless create_git_repository(force: force)
Rails.logger.info("create_repository #{disk_path} vcs_type #{vcs_type} "\
"(#{vcs_type.class})")
return true unless vcs_type == 'hg_git'
Rails.logger.info("Creating Mercurial repository for #{disk_path}")
if gitlab_shell.add_hg_repository(
repository_storage,
disk_path,
namespace_fs_pathname,
in_subgroup: !group.nil? && !group.parent_id.nil?)
true
else
errors.add(:base, 'Failed to create hg repository')
false
end
def in_subgroup?
!group.nil? && !group.parent_id.nil?
end
def create_git_repository(force: false)
def create_repository(force: false)
# Forked import is handled asynchronously
return if forked? && !force
......
......@@ -201,15 +201,6 @@ def hook_attrs
def create_repo!(raw_repository)
gitlab_shell.create_wiki_repository(project)
if project.vcs_type == 'hg_git'
# we don't care about subgroup hgrc, it's the job of the main
# project repository to ensure its consistency
gitlab_shell.add_hg_repository(project.repository_storage,
disk_path,
project.namespace.full_path
)
end
raise CouldNotCreateWikiError unless raw_repository.exists?
repository.after_create
......
......@@ -1160,11 +1160,11 @@ def repository_event(event, tags = {})
end
def initialize_raw_repository
cls = project.vcs_type == 'hg_git' ? Gitlab::Mercurial::HgGitRepository : Gilab::Git::Repository
cls.new(project.repository_storage,
disk_path + '.git',
repo_type.identifier_for_subject(project),
project.full_path)
Gitlab::VCS::repository_class(project.vcs_type).new(
project.repository_storage,
disk_path + '.git',
repo_type.identifier_for_subject(project),
project.full_path)
end
end
......
......@@ -60,8 +60,8 @@ def initialize(storage, relative_path, gl_repository, gl_project_path)
@hg_relative_path = relative_path.sub(/\.git$/, '.hg')
@name = @relative_path.split("/").last
@hgpath = File.join(Gitlab.config.repositories.storages.fetch(storage).hg_disk_path,
@hg_relative_path)
@hg_storage_root = Gitlab.config.repositories.storages.fetch(storage).hg_disk_path
@hgpath = File.join(@hg_storage_root, @hg_relative_path)
end
def to_s
......@@ -103,7 +103,9 @@ def exists?
gitaly_repository_client.exists?
end
def create_repository
# named_args is accepted for uniformity with Mercurial repository
# classes
def create_repository(**named_args)
wrapped_gitaly_errors do
gitaly_repository_client.create_repository
end
......
# Index of the line in lines matching a given regexp
def match_idx(lines, rx)
lines.each_with_index do |line, i|
......@@ -10,6 +11,83 @@ module Gitlab
module Mercurial
class HgGitRepository < Gitlab::Git::Repository
DEFAULT_HGRC = [
"# This is the specific configuration for this repository",
"# You may modify it freely at your will.",
"#",
"# By default, it includes the configuration from the enclosing group",
"# but all the settings defined in the present file will take precedence",
"# as long as they are below the %include line",
"# You may also remove the %include line altogether if you prefer.",
"",
"# group-level configuration",
"%include <GROUP_HGRC_RPATH>",
""].join("\n").freeze
DEFAULT_SUBGROUP_HGRC = [
"# This is the Mercurial configuration for this subgroup.",
"# You may modify it freely at your will.",
"#",
"# By default, it includes the configuration from the enclosing",
"# group, but all the settings defined in the present file will",
"# take precedence as long as they are below the %include line",
"# You may also remove the %include line altogether if you prefer.",
"",
"# enclosing group configuration",
"%include ../hgrc",
""].join("\n").freeze
def create_repository(**named_args)
# at the time being all named_args are Mercurial specific. Still,
# passing explicitely is more future proof
super(**named_args)
create_hg_repository(**named_args)
end
# Create the Mercurial repository only
#
# This is what a FS based native Mercurial class would do
#
# - namespace_fs_path: the path of the directory for the parent
# namespace config files
# - in_subgroup: true is the parent namespace is a subgroup
def create_hg_repository(namespace_fs_path:, in_subgroup:)
Rails.logger.info(
"Creating Mercurial repository at #{@hg_relative_path} "\
"namespace path=#{namespace_fs_path} "\
"in_subgroup: #{in_subgroup}")
begin
out, status = popen(
[Gitlab.config.mercurial.bin_path, "init", @hgpath],
# Rails.root can be a Mercurial repo, that can lead to
# complications. Let's run from a path that's very unlikely
# to be one:
@hg_storage_root,
{ 'HGRCPATH' => Gitlab::Mercurial.hgrc_path,
})
if status != 0
raise HgError, "Could not execute `hg init` for #{@hgpath}: #{out}"
end
File.write(File.join(@hgpath, '.hg', 'hgrc'),
DEFAULT_HGRC.sub('<GROUP_HGRC_RPATH>',
hgrc_inherit_path(namespace_fs_path)))
if in_subgroup
ns_path = Pathname(@hg_storage_root).join(namespace_fs_path)
ns_hgrcf = ns_path.join('hgrc')
unless File.exist?(ns_hgrcf)
FileUtils.mkdir_p(ns_path)
File.write(ns_hgrcf, DEFAULT_SUBGROUP_HGRC)
end
end
end
true
rescue => err
Rails.logger.error("Failed to add Mercurial repository for #{storage}/#{name}: #{err}")
false
end
def merge(user, source_sha, target_branch, message)
logprefix = "hg_merge for #{@relative_path} "\
"source_sha=#{source_sha} target_branch=#{target_branch}"
......@@ -330,17 +408,13 @@ def multi_action(user, branch_name:, message:, actions:,
end
# Compute path to a repo namespace HGRC, ready for inclusion from repo's HGRC.
#
# all parameters are supposed to be relative from the same root or absolute
# namespace_path: must be relative to the storage root, as @relative_path
# is.
#
# Returns: path as a string
def self.compute_hgrc_inherit_path(repo_path, namespace_path)
dot_hg = Pathname(repo_path).join('.hg')
Pathname(namespace_path).join('hgrc').relative_path_from(dot_hg).to_s
end
def hgrc_inherit_path(namespace_path)
self.class.compute_hgrc_inherit_path(@hg_relative_path, namespace_path)
Pathname(namespace_path).join('hgrc')
.relative_path_from(File.join(@hg_relative_path, '.hg')).to_s
end
def hgrc_main_path
......
......@@ -51,11 +51,21 @@ def generate_and_link_secret_token
# Convenience methods for initializing a new repository with a Project model.
def create_project_repository(project)
create_repository(project.repository_storage, project.disk_path, project.full_path)
create_repository(project.repository_storage,
project.disk_path,
project.full_path,
vcs_type: project.vcs_type,
namespace_fs_path: project.namespace_fs_pathname,
in_subgroup: project.in_subgroup?)
end
def create_wiki_repository(project)
create_repository(project.repository_storage, project.wiki.disk_path, project.wiki.full_path)
create_repository(project.repository_storage,
project.wiki.disk_path,
project.wiki.full_path,
vcs_type: project.vcs_type,
namespace_fs_path: project.namespace_fs_pathname,
in_subgroup: project.in_subgroup?)
end
# Init new repository
......@@ -63,99 +73,29 @@ def create_wiki_repository(project)
# storage - the shard key
# disk_path - project disk path
# gl_project_path - project name
# vcs_type - VCS type. Defaults to Git like all Heptapod internals soon
# will do, to restore compatibility with Git oriented tests
#
# Ex.
# create_repository("default", "path/to/gitlab-ci", "gitlab/gitlab-ci")
#
def create_repository(storage, disk_path, gl_project_path)
def create_repository(storage, disk_path, gl_project_path,
vcs_type: 'git', **named_args)
relative_path = disk_path.dup
relative_path << '.git' unless relative_path.end_with?('.git')
# During creation of a repository, gl_repository may not be known
# because that depends on a yet-to-be assigned project ID in the
# database (e.g. project-1234), so for now it is blank.
repository = Gitlab::Git::Repository.new(storage, relative_path, '', gl_project_path)
wrapped_gitaly_errors { repository.gitaly_repository_client.create_repository }
Gitlab::VCS::repository_class(vcs_type)
.new(storage, relative_path, '', gl_project_path)
.create_repository(**named_args)
true
rescue => err # Once the Rugged codes gets removes this can be improved
Rails.logger.error("Failed to add repository #{storage}/#{disk_path}: #{err}") # rubocop:disable Gitlab/RailsLogger
false
end
DEFAULT_HGRC = [
"# This is the specific configuration for this repository",
"# You may modify it freely at your will.",
"#",
"# By default, it includes the configuration from the enclosing group",
"# but all the settings defined in the present file will take precedence",
"# as long as they are below the %include line",
"# You may also remove the %include line altogether if you prefer.",
"",
"# group-level configuration",
"%include <GROUP_HGRC_RPATH>",
""].join("\n").freeze
DEFAULT_SUBGROUP_HGRC = [
"# This is the Mercurial configuration for this subgroup.",
"# You may modify it freely at your will.",
"#",
"# By default, it includes the configuration from the enclosing",
"# group, but all the settings defined in the present file will",
"# take precedence as long as they are below the %include line",
"# You may also remove the %include line altogether if you prefer.",
"",
"# enclosing group configuration",
"%include ../hgrc",
""].join("\n").freeze
# Init new Mercurial repository
#
# storage - project's storage name
# name - project disk path
#
# Ex.
# add_hg_git_repository("/path/to/storage", "gitlab/gitlab-ci")
#
def add_hg_repository(storage, name, namespace_fs_path, in_subgroup: false)
hg_relative_path = name.dup
hg_relative_path << '.hg' unless hg_relative_path.end_with?('.hg')
Rails.logger.info(
"Creating Mercurial repository at #{hg_relative_path} "\
"namespace path=#{namespace_fs_path} "\
"in_subgroup: #{in_subgroup}")
begin
root = Pathname(
Gitlab.config.repositories.storages[storage].hg_disk_path)
ns_path = root.join(namespace_fs_path)
hg_repo_path = root.join(hg_relative_path)
gitlab_shell_fast_execute_raise_error(
[Gitlab.config.mercurial.bin_path, "init", hg_repo_path.to_s],
{ 'HGRCPATH' => Gitlab::Mercurial.hgrc_path,
})
ns_hgrc_incl_path = Gitlab::Mercurial::HgGitRepository::compute_hgrc_inherit_path(
hg_repo_path, ns_path)
File.write(hg_repo_path.join('.hg', 'hgrc'),
DEFAULT_HGRC.sub('<GROUP_HGRC_RPATH>', ns_hgrc_incl_path))
if in_subgroup
ns_hgrcf = ns_path.join('hgrc')
unless File.exist?(ns_hgrcf)
FileUtils.mkdir_p(ns_path)
File.write(ns_hgrcf, DEFAULT_SUBGROUP_HGRC)
end
end
end
# Note for non-rubyists: up to now we had no need of this because
# the last statement was File.write, which returns the number of bytes
# written. Now it can be an 'if', returning nil
true
rescue => err
Rails.logger.error("Failed to add Mercurial repository for #{storage}/#{name}: #{err}")
false
end
def import_wiki_repository(project, wiki_formatter)
import_repository(project.repository_storage, wiki_formatter.disk_path, wiki_formatter.import_url, project.wiki.full_path)
end
......
module Gitlab
module VCS
class << self
def repository_class(vcs_type)
vcs_type == 'hg_git' ? Gitlab::Mercurial::HgGitRepository : Gitlab::Git::Repository
end
end
end
end
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment