Class: Gitolite::GitoliteAdmin

Inherits:
Object
  • Object
show all
Defined in:
lib/gitolite/gitolite_admin.rb

Constant Summary collapse

DEFAULTS =

Default settings

{
  # clone/push url settings
  git_user: 'git',
  hostname: 'localhost',

  # Commit settings
  author_name: 'gitolite-rugged gem',
  author_email: '[email protected]',
  commit_msg: 'Commited by the gitolite-rugged gem',

  # Gitolite-Admin settings
  config_dir: "conf",
  key_dir: "keydir",
  key_subdir: "",
  config_file: "gitolite.conf",
  lock_file_path: '.lock',

  # Repo settings
  update_on_init: true,
  reset_before_update: true
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, settings = {}) ⇒ GitoliteAdmin

Intialize with the path to the gitolite-admin repository

Settings:

Connection

:git_user: The git user to SSH to (:[email protected]: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.


76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# 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

Instance Attribute Details

#repoObject

Returns the value of attribute repo


5
6
7
# File 'lib/gitolite/gitolite_admin.rb', line 5

def repo
  @repo
end

Class Method Details

.admin_url(settings) ⇒ Object


52
53
54
# 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) ⇒ Boolean

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

Returns:

  • (Boolean)

35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 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

Instance Method Details

#add_key(key) ⇒ Object


142
143
144
145
146
147
148
# 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

#applyObject

Push back to origin


226
227
228
# File 'lib/gitolite/gitolite_admin.rb', line 226

def apply
  @repo.push('origin', ['refs/heads/master'], credentials: @credentials)
end

#configObject


127
128
129
# File 'lib/gitolite/gitolite_admin.rb', line 127

def config
  @config ||= load_config
end

#config=(config) ⇒ Object


132
133
134
# File 'lib/gitolite/gitolite_admin.rb', line 132

def config=(config)
  @config = config
end

#relative_config_fileObject

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


115
116
117
# File 'lib/gitolite/gitolite_admin.rb', line 115

def relative_config_file
  File.join(@settings[:config_dir], @settings[:config_file])
end

#relative_key_dirObject

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


123
124
125
# File 'lib/gitolite/gitolite_admin.rb', line 123

def relative_key_dir
  File.join(@settings[:key_dir], @settings[:key_subdir])
end

#reload!Object

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


169
170
171
172
# File 'lib/gitolite/gitolite_admin.rb', line 169

def reload!
  @ssh_keys = load_keys
  @config = load_config
end

#reset!Object

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


162
163
164
# File 'lib/gitolite/gitolite_admin.rb', line 162

def reset!
  @repo.reset('origin/master', :hard)
end

#rm_key(key) ⇒ Object


151
152
153
154
155
156
157
# 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) ⇒ Object

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


177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# 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_applyObject

Commits all staged changes and pushes back to origin


232
233
234
235
# File 'lib/gitolite/gitolite_admin.rb', line 232

def save_and_apply()
  save
  apply
end

#ssh_keysObject


137
138
139
# File 'lib/gitolite/gitolite_admin.rb', line 137

def ssh_keys
  @ssh_keys ||= load_keys
end

#transactionObject

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


241
242
243
244
245
246
247
248
# File 'lib/gitolite/gitolite_admin.rb', line 241

def transaction
  get_lock do
    yield

    # Push all changes
    apply
  end
end

#updateObject

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


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# 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