gitgolem 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --no-private
2
+ --title 'Golem API Documentation'
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "yard", "~> 0.6.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ gem "bluecloth"
14
+ gem "test-unit", "~> 1" #works both for 1.8 and 1.9, backward compatible
15
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 PoTa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # Golem
2
+
3
+ Golem provides an easy way to host and manage access to git repositories on a server under a single user.
4
+
5
+ ## Gem and library name
6
+
7
+ The library name is `Golem`, but the gem is called `gitgolem`.
8
+ After installing you could require either 'golem' or 'gitgolem'.
9
+
10
+ ## How it works
11
+
12
+ Golem's main goals are:
13
+
14
+ * host git repositories under a single user,
15
+ * manage access to repositories on a per-user basis,
16
+ * store users and keys in a database,
17
+ * to be simple as possible, but still extendable.
18
+
19
+ Golem is not designed to handle complex access rules, altough it may be extended to achieve that. If you need more refined rules, like per-branch or per-path control
20
+ you should check out {https://github.com/sitaramc/gitolite gitolite}, which has far superior features in this regard.
21
+
22
+ The git flow that golem supports is:
23
+
24
+ * you have a specific shell user that "hosts" golem,
25
+ * golem places your users ssh keys in this (shell) user's home directory (_~/.ssh/authorized\_keys_),
26
+ * your users use a git remote like _golem\_host\_user@your\_server:repository.git_,
27
+ * when a user git pushes/pulls, his git connects via ssh, sshd invokes golem's authorization command (via the _authorized\_keys_ file),
28
+ * golem authorizes the user for the given repository and invokes _git-shell_ if access granted.
29
+
30
+ ## Configuration
31
+
32
+ Golem supports the following configuration variables:
33
+
34
+ * `db`: the database to use, currently postgres ('postgres://...') and static ('static') supported,
35
+ * `user_home`: the directory where the .ssh/authorized_keys file should be written, defaults to `HOME` environment variable,
36
+ * `repository_dir`: path to the git repositories, may be relative to `user_home`,
37
+ * `cfg_path`: path to config file, if not set searched for as (in this order):
38
+ * `GOLEM_CONFIG` environment variable (if set),
39
+ * 'golem.conf.rb' relative to `GOLEM_BASE` environment variable (if set),
40
+ * /usr/local/etc/golem/golem.conf.rb,
41
+ * /usr/local/etc/golem.conf.rb,
42
+ * /etc/golem/golem.conf.rb,
43
+ * /etc/golem.conf.rb,
44
+ * ~/golem.conf.rb,
45
+ * if found it is required (e.g. loaded), otherwise set to `base_dir + "/golem.conf.rb"` after configuration,
46
+ * `base_dir`: convenience feature, may be used to store installation, if not explicitly set defaults to:
47
+ * `GOLEM_BASE` environment variable (if set),
48
+ * basedir of `cfg_path` if file exists,
49
+ * basedir of the library itself (e.g. the gem path),
50
+ * `bin_dir`: where the executable is installed, defaults to `base_dir + "/bin"`,
51
+ * `hooks_dir`: where the hooks are installed, defaults to `base_dir + "/hooks"`,
52
+ * `keys_file_use_command`: controls how to use `.ssh/authorized_keys` (_environment=""_ or _command=""_), see {file:README#keys_file authorized\_keys},
53
+ * `keys_file_ssh_opts`: ssh options to place in `.ssh/authorized_keys`, see {file:README#keys_file authorized\_keys}.
54
+
55
+ <a name="keys_file"></a>
56
+ ## Git and .ssh/authorized_keys
57
+
58
+ Git supports SSH as the transport protocol for pulling and pushing, and assumes SSH for remotes like _user@server:/path/to/project.git_. With ssh remotes git executes remote commands, like
59
+ `git-receive-pack '/path/to/project.git'` (this is stored in `SSH_ORIGINAL_COMMAND` environment variable for the curious) when doing something like `git clone user@server:/path/to/project.git`.
60
+ Golem authorizes users so it must act before the actual git command runs. Key-based authentication is very popular and the `.ssh/authorized_keys` file allows a few possibilities to achieve what
61
+ golem tries to do, so it seems a natural fit. **Please note:** golem won't work without key-based authentication, as it relies content placed in the `.ssh/authorized_keys` file.
62
+
63
+ Golem by default requires that you (control your SSHD's options and) set the users shell to `golem-shell` (wherever it is installed) that is "hosting" the repositories. With that setup golem can
64
+ simply place lines like `environment="GOLEM_USER=username" ssh-dss AAA...` (where `AAA...` is the key) in the `.ssh/authorized_keys` file and `golem-shell` simply reads that environment
65
+ variable. (**Please note:** SSHD by default does not permit changing environment variables, you have to enable it with setting `PermitUserEnvironment` to `yes`.) However this needs
66
+ that the user's shell is set to `golem-shell`, so golem provides a configuration variable, if you can't or simply don't want to change the user's shell. When `keys_file_use_command` is true golem
67
+ writes lines like `command="/path/to/golem auth 'username'" ssh-dss AAA...` instead. **Please note:**
68
+
69
+ Golem supports another configuration variable called `keys_file_ssh_opts`, which is simply placed after the _environment=""_ or _command=""_ block. If `keys_file_use_command` is false (using
70
+ _environment=""_) golem simply injects the string into the lines, however if `keys_file_use_command` is true and `keys_file_ssh_opts` is not set (is `nil`) golem uses
71
+ {Golem::Command::UpdateKeysFile::SSH\_OPTS\_COMMAND\_DEFAULT} (if it is not `nil` golem uses the configuration value). The reasoning behind this distinction is golem assumes you control
72
+ your SSHD's settings if using _environment=""_, but you may not (want to) set (global) restrictions when using _command=""_. The final line looks something like
73
+ `environment="GOLEM_USER=username",ssh,opts ssh-dss AAA...` or `command="/path/to/golem auth 'username'",ssh,opts ssh-dss AAA...`.
74
+
75
+ **Please note:** golem does not overwrite the whole `.ssh/authorized_keys` file.
76
+
77
+ ## Access control
78
+
79
+ Golem's access control by default is very simple. It assumes a repository belongs to a single user, so it grants access to a given repository only to its owner.
80
+ For a very basic setup this should be enough. However for more complex setup golem does not want to assume how you want to store your users and repositories, so
81
+ it simply doesn't. You can fine tune your environment to suit your specific needs with overriding {Golem::Access.check} (its arguments are the username, the repository
82
+ name and the git command to run (e.g. one of upload-pack, upload-archive and receive-pack)).
83
+
84
+ Golem's access control is done at the very beginning, before git-shell is run, so it's not suitable for per-branch or per-directory control. This can be achieved by hooks.
85
+ You should check out {https://github.com/sitaramc/gitolite gitolite}, which supports exactly that (and more). If you want you can place
86
+ {https://github.com/sitaramc/gitolite gitolite}'s hooks in golem's `hooks_dir` and achieve the same results (this requires deeper understanding of git, so
87
+ please be aware).
88
+
89
+ ## Public access
90
+
91
+ Golem does not support providing public (read-only anonymous) access to git repositories as it relies on SSH's key-based authentication. However there are a couple of alternatives
92
+ to solve this, with each having its pros and cons: {http://progit.org/book/ch4-5.html serving the repository as a static website}, {http://progit.org/book/ch4-6.html using GitWeb}
93
+ or {http://progit.org/book/ch4-9.html using Git Daemon}.
94
+
95
+ ## Database
96
+
97
+ Golem currently supports postgres and a static databases only, but it should be trivial to extend it (contributions are always welcome). At least users and repositories
98
+ should have names, keys should have an attribute named `key` that is the whole key (e.g. cat id_rsa.pub).
99
+
100
+ The {Golem::DB::Static static database} is suitable for small installations (where an rdbms would be an overkill), to use it simply write:
101
+
102
+ Golem.configure do |cfg|
103
+ cfg.db = 'static'
104
+ Golem::DB.setup do |db|
105
+ db.add_user 'test_user'
106
+ db.add_repository 'test_repository', 'test_user'
107
+ db.add_key 'test_user', 'test_key'
108
+ end
109
+ end
110
+
111
+ The postgres database stores data in 3 tables (users, repositories, keys) by default, and can be used with setting the db variable to the postgres url (e.g. `postgres://user:pw@host/db`).
112
+ A sample schema can be found in `lib/golem/db/postgres.sql`, and it is imported by {Golem::DB::Pg#setup} (please note: {Golem::DB.setup} forwards to it, should be called
113
+ only once). A minimal setup for postgres would be:
114
+
115
+ Golem.configure do |cfg|
116
+ cfg.db = "postgres://user:pwd@host/dbname"
117
+ cfg.bin_dir = "/usr/local/bin"
118
+ end
119
+
120
+ A more complex setup with collaborators:
121
+
122
+ Golem.configure do |cfg|
123
+ Golem::DB::Pg.class_eval do
124
+ #add method to query collaborators
125
+ def collaborators(opts = {})
126
+ opts[:table] = "collaborators join users on collaborators.user_name=users.name"
127
+ get(opts)
128
+ end
129
+
130
+ #add method to check if user is a collaborator of a given repository
131
+ def collaborator?(user, repo)
132
+ collaborators(:user_name => user, :repository_name => repo, :fields => :name).length > 0
133
+ end
134
+
135
+ #override setup to add our collaborators table
136
+ alias_method :setup_orig, :setup
137
+ def setup
138
+ setup_orig
139
+ @connection.exec("CREATE TABLE collaborators (user_name varchar(32) NOT NULL REFERENCES users (name), repository_name varchar(32) NOT NULL REFERENCES repositories (name), PRIMARY KEY (user_name, repository_name));")
140
+ end
141
+ end
142
+ Golem::DB.class_eval do
143
+ #add method proxy to check collaborator status
144
+ def self.collaborator?(user, repo)
145
+ db.collaborator?(user, repo)
146
+ end
147
+ end
148
+ Golem::Access.class_eval do
149
+ #override check to grant access to collaborators
150
+ class << self; alias_method :check_orig, :check end
151
+ def self.check(user, repo, gitcmd)
152
+ Golem::DB.collaborator?(user, repo) || check_orig(user, repo, gitcmd)
153
+ end
154
+ end
155
+ cfg.db = 'postgres://user:pwd@host/dbname'
156
+ end
157
+
158
+ ## Commands
159
+
160
+ Golem provides an executable, and supports a few commands to easily automate the administration:
161
+
162
+ * auth: is used for authorization by sshd,
163
+ * clear\_repositories: clear old data (e.g. suitable for cron),
164
+ * create\_repository: create a repository manually (new repositories are created automatically by golem on first access),
165
+ * delete\_repository: delete a repository manually,
166
+ * environment: list configuration variables,
167
+ * save\_config: save configuration variables,
168
+ * setup\_db: setup database schema (useful for postgres only),
169
+ * update\_hooks: update hooks in every repository,
170
+ * update\_keys\_file: update the .ssh/authorized_keys file.
171
+
172
+ You can get details about commands running `golem -h` or `--help`.
173
+
174
+ Golem provides another executable called `golem-shell`, which is a convenience script that calls `golem auth`.
175
+
176
+ ## Contributing to golem
177
+
178
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
179
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
180
+ * Fork the project
181
+ * Start a feature/bugfix branch
182
+ * Commit and push until you are happy with your contribution
183
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
184
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
185
+
186
+ ## Copyright
187
+
188
+ Copyright (c) 2011 PoTa. See LICENSE.txt for
189
+ further details.
190
+
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ require './lib/golem/version.rb'
14
+ Jeweler::Tasks.new do |gem|
15
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
16
+ gem.name = "gitgolem"
17
+ gem.homepage = "http://github.com/eLod/golem"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{Gem to host git repositories.}
20
+ gem.description = %Q{Golem provides an easy way to host and manage access to git repositories on a server under a single user.}
21
+ gem.email = "pota@mosfet.hu"
22
+ gem.authors = ["PoTa"]
23
+ gem.version = Golem::Version::STRING
24
+ gem.executables = ["golem", "golem-shell"]
25
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
26
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
27
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
28
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
29
+ end
30
+ Jeweler::RubygemsDotOrgTasks.new
31
+
32
+ require 'rake/testtask'
33
+ Rake::TestTask.new(:test) do |test|
34
+ test.libs << 'lib' << 'test'
35
+ test.pattern = 'test/**/test_*.rb'
36
+ test.verbose = true
37
+ end
38
+
39
+ require 'rcov/rcovtask'
40
+ Rcov::RcovTask.new do |test|
41
+ test.libs << 'test'
42
+ test.pattern = 'test/**/test_*.rb'
43
+ test.verbose = true
44
+ end
45
+
46
+ task :default => :test
47
+
48
+ require 'yard'
49
+ YARD::Rake::YardocTask.new
data/TODO ADDED
@@ -0,0 +1,24 @@
1
+ -conf file placement (move to /etc/_golem_/golem.conf.rb)
2
+ -conf file bug, does not find by /etc/golem.conf.rb
3
+
4
+
5
+ -auth command add separately
6
+ -auth command use GOLEM_USER env
7
+ -auth command fix fixed 'repositories/' path
8
+ -update-keys command add option to use ENV, what should be the default? - ENV should be default, but add doc to use 'orig' setup
9
+ -update-keys command make SSH_OPTS configurable
10
+ -update-keys command auth_cmd bug with '-' inside -- INVALID
11
+
12
+
13
+ -add read/write? method (e.g. gitcmd) for convenience in Golem::Access
14
+
15
+
16
+ -add command for db.setup
17
+ -add env shortcut for environment (and look for others)
18
+
19
+
20
+ -make git commands no output (is sent back, e.g. "Initialized empty Git repository in /home/git/repositories/golem.git/")
21
+
22
+
23
+ -add docs about anon read (web + git:// with git daemon)
24
+ -add complex example to readme (e.g. with .access overriden and with extra schema [collaborators, admins]) - flip order of db and access @ readme
data/bin/golem ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+ require 'golem'
3
+ Golem::Parser.run(ARGV)
data/bin/golem-shell ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require 'golem'
3
+ ENV['SSH_ORIGINAL_COMMAND'] = ARGV[1] if ARGV.length == 2 && ARGV.first == "-c"
4
+ Golem::Parser.run(["auth"])
data/lib/gitgolem.rb ADDED
@@ -0,0 +1 @@
1
+ require 'golem'
data/lib/golem.rb ADDED
@@ -0,0 +1,21 @@
1
+ # Golem provides an easy way to host and manage access to git repositories on a server under a single user. More details can be found:
2
+ # * for configuration at {Golem::Config},
3
+ # * for database handling at {Golem::DB},
4
+ # * for access control at {Golem::Access},
5
+ # * for commands at {Golem::Command},
6
+ # * for general help at {file:README}.
7
+ module Golem
8
+ autoload :Access, "golem/access"
9
+ autoload :Command, "golem/command"
10
+ autoload :Config, "golem/config"
11
+ autoload :DB, "golem/db"
12
+ autoload :Parser, "golem/parser"
13
+ autoload :Version, "golem/version"
14
+
15
+ # Configure Golem.
16
+ # @see Golem::Config.configure
17
+ def self.configure(opts_or_path = nil, &block)
18
+ Config.configure(opts_or_path, &block)
19
+ self
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ # Access control, implements basic control, may be overriden (see {check}).
2
+ module Golem::Access
3
+ # Main access control, checks if user is the owner of the repository. When overriden +gitcmd+ may be used to determine R/W access.
4
+ # @param [String] user username,
5
+ # @param [String] repo repository name,
6
+ # @param [String] gitcmd git command (one of +upload-pack+, +upload-archive+, +receive-pack+).
7
+ # @return [Boolean] result.
8
+ def self.check(user, repo, gitcmd)
9
+ Golem::DB.repositories(:user_name => user, :name => repo, :fields => :name).length > 0
10
+ end
11
+
12
+ # @return [Array] list of usernames.
13
+ def self.users
14
+ Golem::DB.users(:fields => :name, :return => :array)
15
+ end
16
+
17
+ # @return [Hash] username => [array of keystrings] pairs.
18
+ def self.ssh_keys
19
+ Golem::DB.ssh_keys(:fields => [:name, :key], :return => :array).inject({}) do |memo, (user, key)|
20
+ if memo.key?(user)
21
+ memo[user] << key
22
+ else
23
+ memo[user] = [key]
24
+ end
25
+ memo
26
+ end
27
+ end
28
+
29
+ # @return [Array] list of repository names.
30
+ def self.repositories
31
+ Golem::DB.repositories(:fields => :name, :return => :array)
32
+ end
33
+
34
+ # Convenience method to check if requested access type is read (e.g. command was +receive-pack+).
35
+ # @return [Boolean] if read access was requested.
36
+ def self.read?(gitcmd)
37
+ gitcmd == "receive-pack"
38
+ end
39
+
40
+ # Convenience method to check if requested access type is write (e.g. command was +upload-pack+ or +upload-archive+).
41
+ # @return [Boolean] if write access was requested.
42
+ def self.write?(gitcmd)
43
+ !!gitcmd.match(/\Aupload-(pack|archive)\z/)
44
+ end
45
+ end
@@ -0,0 +1,107 @@
1
+ # Namespace for commands.
2
+ module Golem::Command
3
+ # List of command names as symbols.
4
+ COMMANDS = [:auth, :clear_repositories, :create_repository, :delete_repository, :environment, :save_config, :setup_db, :update_hooks, :update_keys_file]
5
+ # Hash of aliases.
6
+ ALIASES = {
7
+ :clear_repositories => ["clear-repositories", "clear-repos", "clear_repos"],
8
+ :create_repository => ["create-repository", "create-repo", "create_repo"],
9
+ :delete_repository => ["delete-repository", "delete-repo", "delete_repo"],
10
+ :environment => ["env"],
11
+ :save_config => ["save-config", "save"],
12
+ :setup_db => ["setup-db", "setup"],
13
+ :update_hooks => ["update-hooks"],
14
+ :update_keys_file => ["update-keys-file", "update-keys", "update_keys"],
15
+ }
16
+
17
+ autoload :Auth, "golem/command/auth"
18
+ autoload :ClearRepositories, "golem/command/clear_repositories"
19
+ autoload :CreateRepository, "golem/command/create_repository"
20
+ autoload :DeleteRepository, "golem/command/delete_repository"
21
+ autoload :Environment, "golem/command/environment"
22
+ autoload :SaveConfig, "golem/command/save_config"
23
+ autoload :SetupDb, "golem/command/setup_db"
24
+ autoload :UpdateHooks, "golem/command/update_hooks"
25
+ autoload :UpdateKeysFile, "golem/command/update_keys_file"
26
+
27
+ # Run a command.
28
+ # @param [Symbol, String] cmd command name to run,
29
+ # @param [Hash] opts options, see {Base#initialize},
30
+ # @param *args arguments for the command.
31
+ def self.run(cmd, opts = {:verbose => true}, *args)
32
+ find(cmd).new(opts).run(*args)
33
+ end
34
+
35
+ # Get command usage to display in help message.
36
+ # @param [Symbol, String] cmd command name.
37
+ # @return [String] usage text or empty string.
38
+ def self.usage(cmd)
39
+ cmd = find(cmd)
40
+ cmd.const_defined?(:USAGE) ? cmd::USAGE : ""
41
+ end
42
+
43
+ # Find command class by name.
44
+ # @raise [NameError] if class (constant) not found.
45
+ # @param [Symbol, String] cmd command name to search for.
46
+ # @return [Class] command class.
47
+ def self.find(cmd)
48
+ cmd = ALIASES.find {|key, a| a.include?(cmd.to_s)}.first if ALIASES.any? {|key, aliases| aliases.include?(cmd.to_s)}
49
+ abort "Command not understood." unless COMMANDS.include?(cmd.to_sym)
50
+ const_get cmd.to_s.split("_").collect {|p| p.capitalize}.join.to_sym
51
+ end
52
+
53
+ # Abstract class for commands.
54
+ # @abstract Subclass and override {#run} to implement a custom Command class.
55
+ class Base
56
+ # @param [Hash] opts options
57
+ # @option opts [Boolean] :verbose control verbosity.
58
+ def initialize(opts)
59
+ @opts = opts
60
+ end
61
+
62
+ # Check verbosity.
63
+ def verbose?
64
+ !!@opts[:verbose]
65
+ end
66
+
67
+ # Run the command.
68
+ def run
69
+ abort "Bad command."
70
+ end
71
+
72
+ # Run another command.
73
+ # @param [Symbol] cmd the command to run,
74
+ # @param *args arguments for the command.
75
+ def command(cmd, *args)
76
+ Golem::Command.run(cmd, @opts, *args)
77
+ end
78
+ end
79
+
80
+ # Mixin for hook management.
81
+ module ManageHooks
82
+ # Install hooks into repository.
83
+ # @param [String] repo repository name.
84
+ def install_hooks(repo)
85
+ path = Golem::Config.repository_path(repo)
86
+ Dir.entries(Golem::Config.hooks_dir).each do |hook|
87
+ hook_src = Golem::Config.hook_path(hook)
88
+ next unless File.file?(hook_src) && File.stat(hook_src).executable? && hook[0..0] != "."
89
+ File.symlink(hook_src, path + '/hooks/' + hook)
90
+ print "Hook installed from #{hook_src} to #{path}/hooks/#{hook}.\n" if verbose?
91
+ end if File.directory?(Golem::Config.hooks_dir)
92
+ end
93
+
94
+ # Remove hooks from repository (please note: this *deletes* old hooks).
95
+ # @param [String] repo repository name.
96
+ def clear_hooks(repo)
97
+ path = Golem::Config.repository_path(repo)
98
+ Dir.entries(path + "/hooks").each do |hook|
99
+ hook_src = path + "/hooks/" + hook
100
+ File.delete(hook_src) if File.symlink?(hook_src) && ! File.file?(hook_src)
101
+ next unless File.file?(hook_src) && File.stat(hook_src).executable? && hook[0..0] != "."
102
+ File.delete(hook_src)
103
+ print "Hook removed from #{hook_src}.\n" if verbose?
104
+ end
105
+ end
106
+ end
107
+ end