class Gitolite::GitoliteAdmin

Constants

DEFAULTS

Default settings

Attributes

repo[RW]

Public Class Methods

admin_url(settings) click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 52
def admin_url(settings)
  ['ssh://', settings[:git_user], '@', settings[:host], '/gitolite-admin.git'].join
end
is_gitolite_admin_repo?(dir) click to toggle source

Checks if the given path is a gitolite-admin repository A valid repository contains a conf folder, keydir folder, and a configuration file within the conf folder

# File lib/gitolite/gitolite_admin.rb, line 35
def is_gitolite_admin_repo?(dir)
  # First check if it is a git repository
  begin
    repo = Rugged::Repository.new(dir)
    return false if repo.empty?
  rescue Rugged::RepositoryError, Rugged::OSError
    return false
  end

  # Check if config file, key directory exist
  [ File.join(dir, DEFAULTS[:config_dir]), File.join(dir, DEFAULTS[:key_dir]),
    File.join(dir, DEFAULTS[:config_dir], DEFAULTS[:config_file])
  ].each { |f| return false unless File.exists?(f) }

  true
end
new(path, settings = {}) click to toggle source

Intialize with the path to the gitolite-admin repository

Settings:

Connection

:git_user: The git user to SSH to (:git_user@localhost:gitolite-admin.git), defaults to ‘git’ :private_key: The key file containing the private SSH key for :git_user :public_key: The key file containing the public SSH key for :git_user :host: Hostname for clone url. Defaults to ‘localhost’

Gitolite-Admin

:config_dir: Config directory within gitolite repository (defaults to ‘conf’) :key_dir: Public key directory within gitolite repository (defaults to ‘keydir’) :config_file: Config file to parse (default: ‘gitolite.conf’) **use only when you use the ‘include’ directive of gitolite)** :key_subdir: Where to store gitolite-rugged known keys, defaults to ” (i.e., directly in keydir) :lock_file_path: location of the transaction lockfile, defaults to <gitolite-admin.git>/.lock

The settings hash is forwarded to GitoliteAdmin.new as options.

# File lib/gitolite/gitolite_admin.rb, line 76
def initialize(path, settings = {})
  @path = path
  @settings = DEFAULTS.merge(settings)

  # Ensure SSH key settings exist
  @settings.fetch(:public_key)
  @settings.fetch(:private_key)

  # setup credentials
  @credentials = Rugged::Credentials::SshKey.new(
    username: @settings[:git_user],
    publickey: settings[:public_key],
    privatekey: settings[:private_key]
  )

  @config_dir_path    = File.join(@path, @settings[:config_dir])
  @config_file_path = File.join(@config_dir_path, @settings[:config_file])
  @key_dir_path     = File.join(@path, relative_key_dir)

  @commit_author = { email: @settings[:author_email], name: @settings[:author_name] }

  if self.class.is_gitolite_admin_repo?(path)
    @repo = Rugged::Repository.new(path, credentials: @credentials )
    # Update repository
    if @settings[:update_on_init]
      update
    end
  else
    @repo = clone
  end

  reload!
end

Public Instance Methods

add_key(key) click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 142
def add_key(key)
  unless key.instance_of? Gitolite::SSHKey
    raise GitoliteAdminError, "Key must be of type Gitolite::SSHKey!"
  end

  ssh_keys[key.owner] << key
end
apply() click to toggle source

Push back to origin

# File lib/gitolite/gitolite_admin.rb, line 226
def apply
  @repo.push('origin', ['refs/heads/master'], credentials: @credentials)
end
config() click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 127
def config
  @config ||= load_config
end
config=(config) click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 132
def config=(config)
  @config = config
end
relative_config_file() click to toggle source

Returns the relative directory to the gitolite config file location. I.e., settings/settings Defaults to ‘conf/gitolite.conf’

# File lib/gitolite/gitolite_admin.rb, line 115
def relative_config_file
  File.join(@settings[:config_dir], @settings[:config_file])
end
relative_key_dir() click to toggle source

Returns the relative directory to the public key location. I.e., settings/settings Defaults to ‘keydir/’

# File lib/gitolite/gitolite_admin.rb, line 123
def relative_key_dir
  File.join(@settings[:key_dir], @settings[:key_subdir])
end
reload!() click to toggle source

This method will destroy the in-memory data structures and reload everything from the file system

# File lib/gitolite/gitolite_admin.rb, line 169
def reload!
  @ssh_keys = load_keys
  @config = load_config
end
reset!() click to toggle source

This method will destroy all local tracked changes, resetting the local gitolite git repo to HEAD

# File lib/gitolite/gitolite_admin.rb, line 162
def reset!
  @repo.reset('origin/master', :hard)
end
rm_key(key) click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 151
def rm_key(key)
  unless key.instance_of? Gitolite::SSHKey
    raise GitoliteAdminError, "Key must be of type Gitolite::SSHKey!"
  end

  ssh_keys[key.owner].delete key
end
save(commit_msg = nil) click to toggle source

Writes all changed aspects out to the file system will also stage all changes then commit

# File lib/gitolite/gitolite_admin.rb, line 177
def save(commit_msg = nil)

  # Add all changes to index (staging area)
  index = @repo.index

  #Process config file (if loaded, i.e. may be modified)
  if @config
    new_conf = @config.to_file(path=@config_dir_path)
    index.add(relative_config_file)
  end

  #Process ssh keys (if loaded, i.e. may be modified)
  if @ssh_keys
    files = list_keys.map{|f| relative_key_path(f) }
    keys  = @ssh_keys.values.map{|f| f.map {|t| t.relative_path}}.flatten

    to_remove = (files - keys).each do |key|
      SSHKey.remove(key, @key_dir_path)
      index.remove File.join(relative_key_dir, key)
    end

    @ssh_keys.each_value do |key|
      # Write only keys from sets that has been modified
      next if key.respond_to?(:dirty?) && !key.dirty?
      key.each do |k|
        new_key = k.to_file(@key_dir_path)
        index.add File.join(relative_key_dir, k.relative_path)
      end
    end
  end

  # Write index to git and resync fs
  commit_tree = index.write_tree @repo
  index.write

  commit_author = @commit_author.merge(time: Time.now)

  Rugged::Commit.create(@repo,
    author: commit_author,
    committer: commit_author,
    message: commit_msg || @settings[:commit_msg],
    parents: [repo.head.target],
    tree: commit_tree,
    update_ref: 'HEAD'
  )
end
save_and_apply() click to toggle source

Commits all staged changes and pushes back to origin

# File lib/gitolite/gitolite_admin.rb, line 232
def save_and_apply()
  save
  apply
end
ssh_keys() click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 137
def ssh_keys
  @ssh_keys ||= load_keys
end
transaction() { || ... } click to toggle source

Lock the gitolite-admin directory and yield. After the block is completed, calls apply only. You have to commit your changes within the transaction block

# File lib/gitolite/gitolite_admin.rb, line 241
def transaction
  get_lock do
    yield

    # Push all changes
    apply
  end
end
update() click to toggle source

Updates the repo with changes from remote master Warning: This resets the repo before pulling in the changes.

# File lib/gitolite/gitolite_admin.rb, line 253
def update()

  # Reset --hard repo before update
  if @settings[:reset_before_update]
    reset!
  end

  # Fetch changes from origin
  @repo.fetch('origin', credentials: @credentials )

  # Currently, only merging from origin/master into master is supported.
  master = @repo.references["refs/heads/master"].target
  origin_master = @repo.references["refs/remotes/origin/master"].target

  # Create the merged index in memory
  merge_index = repo.merge_commits(master, origin_master)

  # Complete the merge by comitting it
  merge_commit = Rugged::Commit.create(@repo,
    parents: [ master, origin_master ],
    tree: merge_index.write_tree(@repo),
    message: '[gitolite-rugged] Merged `origin/master` into `master`',
    author: @commit_author,
    committer: @commit_author,
    update_ref: 'refs/heads/master'
  )

  reload!
end

Private Instance Methods

clone() click to toggle source

Clone the gitolite-admin repo to the given path.

The repo is cloned from the url +(:git_user)@(:hostname)/gitolite-admin.git+

The hostname may use an optional :port to allow for custom SSH ports. E.g., +git@localhost:2222/gitolite-admin.git+

# File lib/gitolite/gitolite_admin.rb, line 296
def clone
  Rugged::Repository.clone_at(GitoliteAdmin.admin_url(@settings), File.expand_path(@path), credentials: @credentials )
end
get_lock() { || ... } click to toggle source

Aquire LOCK_EX on the gitolite-admin.git directory . Use GitoliteAdmin.transaction to modify with flock.

# File lib/gitolite/gitolite_admin.rb, line 343
def get_lock
  File.open(lock_file_path, File::RDWR|File::CREAT, 0644) do |file|
    file.sync = true
    file.flock(File::LOCK_EX)

    yield

    file.flock(File::LOCK_UN)
  end
end
list_keys() click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 306
def list_keys
  Dir.glob(@key_dir_path + '/**/*.pub')
end
load_config() click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 301
def load_config
  Config.new(@config_file_path)
end
load_keys() click to toggle source

Loads all .pub files in the gitolite-admin keydir directory

# File lib/gitolite/gitolite_admin.rb, line 320
def load_keys
  keys = Hash.new {|k,v| k[v] = DirtyProxy.new([])}

  list_keys.each do |key|
    new_key = SSHKey.from_file(key)
    owner = new_key.owner

    keys[owner] << new_key
  end

  # Mark key sets as unmodified (for dirty checking)
  keys.values.each{|set| set.clean_up!}

  keys
end
lock_file_path() click to toggle source
# File lib/gitolite/gitolite_admin.rb, line 336
def lock_file_path
  File.expand_path(@settings[:lock_file_path], @path)
end
relative_key_path(key_path) click to toggle source

Returns the relative key path <owner>/<location>/<owner> given an absolute path below the keydir.

# File lib/gitolite/gitolite_admin.rb, line 313
def relative_key_path(key_path)
  Pathname.new(key_path).relative_path_from(Pathname.new(@key_dir_path)).to_s
end