hubbard 0.0.16 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +3 -0
- data/VERSION +1 -1
- data/bin/hub-daemon +11 -0
- data/bin/hubbard +101 -59
- data/commands/add-key.rb +2 -4
- data/commands/add-permission.rb +2 -13
- data/commands/create-project.rb +5 -17
- data/commands/create-repository.rb +2 -2
- data/commands/fork-repository.rb +2 -3
- data/commands/list-forks.rb +4 -1
- data/commands/list-keys.rb +1 -1
- data/commands/list-permissions.rb +7 -20
- data/commands/list-projects.rb +3 -1
- data/commands/list-repositories.rb +1 -1
- data/commands/list-users.rb +4 -3
- data/commands/move-repository.rb +2 -4
- data/commands/remove-key.rb +3 -6
- data/commands/remove-permission.rb +3 -12
- data/commands/rename-project.rb +1 -2
- data/commands/set-description.rb +4 -4
- data/commands/set-visibility.rb +2 -4
- data/hubbard.gemspec +8 -6
- data/lib/project.rb +71 -0
- data/spec/hubbard_spec.rb +36 -29
- data/spec/spec_helper.rb +6 -0
- data/spec/yaml_spec.rb +5 -5
- metadata +23 -10
data/.gitignore
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.18
|
data/bin/hub-daemon
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
4
|
+
require 'hubbard'
|
5
|
+
|
6
|
+
puts "git daemon --base-path #{Hubbard::PROJECTS_PATH} #{Hubbard::PROJECTS_PATH}"
|
7
|
+
|
8
|
+
exec "git daemon --base-path=#{Hubbard::PROJECTS_PATH} #{Hubbard::PROJECTS_PATH}"
|
9
|
+
|
10
|
+
|
11
|
+
|
data/bin/hubbard
CHANGED
@@ -2,17 +2,19 @@
|
|
2
2
|
require 'fileutils'
|
3
3
|
require 'optparse'
|
4
4
|
require 'yaml'
|
5
|
+
require 'shellwords'
|
5
6
|
|
6
7
|
$:.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
7
8
|
require 'hubbard'
|
9
|
+
require 'project'
|
8
10
|
|
9
11
|
FileUtils.mkdir_p(Hubbard::PROJECTS_PATH)
|
10
12
|
FileUtils.mkdir_p(Hubbard::ACCOUNTS_PATH)
|
11
13
|
|
12
14
|
formats = [:text, :yaml]
|
13
|
-
|
14
|
-
|
15
|
-
|
15
|
+
DEFAULTS = { :format => formats.first }
|
16
|
+
OPTIONS = {}
|
17
|
+
OPTS = OptionParser.new do |opts|
|
16
18
|
opts.banner = <<BANNER
|
17
19
|
Usage: hubbard [options] <command>
|
18
20
|
|
@@ -37,88 +39,69 @@ Options:
|
|
37
39
|
BANNER
|
38
40
|
|
39
41
|
opts.on("--private", "Create project with visibility set to private") do |o|
|
40
|
-
|
42
|
+
OPTIONS[:private] = o
|
41
43
|
end
|
42
44
|
opts.on("-f", "--format [FORMAT]", formats,
|
43
45
|
"Output format (#{formats.join(', ')})") do |o|
|
44
|
-
|
46
|
+
OPTIONS[:format] = o
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
50
|
+
class HubbardException < Exception
|
51
|
+
attr_reader :exitstatus
|
52
|
+
def initialize(exitstatus)
|
53
|
+
@exitstatus = exitstatus
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def error(exitstatus,message)
|
58
|
+
raise HubbardException.new(exitstatus), message
|
59
|
+
end
|
60
|
+
|
48
61
|
def next_arg(msg)
|
49
62
|
if ARGV.length < 1
|
50
|
-
|
51
|
-
exit 1
|
63
|
+
error 1, msg
|
52
64
|
end
|
53
65
|
ARGV.shift
|
54
66
|
end
|
55
67
|
|
68
|
+
def rest_args(msg)
|
69
|
+
if ARGV.length < 1
|
70
|
+
error 1, msg
|
71
|
+
end
|
72
|
+
ARGV
|
73
|
+
end
|
74
|
+
|
56
75
|
def check_status(msg)
|
57
76
|
if $!.exitstatus != 0
|
58
|
-
|
59
|
-
exit 1
|
77
|
+
error $!.exitstatus, msg
|
60
78
|
end
|
61
79
|
end
|
62
80
|
|
63
81
|
def validate_project_name(name)
|
64
82
|
if name !~ /#{Hubbard::PROJECT_REGEX}/
|
65
|
-
|
66
|
-
exit 1
|
83
|
+
error 1, "Project names can only contain letter, numbers, and hyphens"
|
67
84
|
end
|
68
85
|
end
|
69
86
|
|
70
87
|
def validate_repository_name(name)
|
71
88
|
if name !~ /#{Hubbard::REPOSITORY_REGEX}/
|
72
|
-
|
73
|
-
exit 1
|
89
|
+
error 1, "Repository names can only contain letter, numbers, and hyphens"
|
74
90
|
end
|
75
91
|
end
|
76
92
|
|
77
93
|
def validate_user_name(name)
|
78
94
|
if name !~ /#{Hubbard::USERNAME_REGEX}/
|
79
|
-
|
80
|
-
exit 1
|
95
|
+
error 1, "User names can only contain letter, numbers, and hyphens"
|
81
96
|
end
|
82
97
|
end
|
83
98
|
|
84
99
|
def validate_action_name(action)
|
85
100
|
unless Hubbard::ACTIONS.member?(action)
|
86
|
-
|
87
|
-
exit 1
|
101
|
+
error 1, "Not a valid action (must be one of: read, write, admin)"
|
88
102
|
end
|
89
103
|
end
|
90
104
|
|
91
|
-
username = next_arg "Please specify the username to run as"
|
92
|
-
|
93
|
-
if ENV['SSH_ORIGINAL_COMMAND']
|
94
|
-
ARGV.clear
|
95
|
-
ENV['SSH_ORIGINAL_COMMAND'].split.each do |arg|
|
96
|
-
ARGV << arg
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
opts.parse!
|
101
|
-
OPTIONS = defaults.merge(options)
|
102
|
-
OPTIONS.freeze
|
103
|
-
|
104
|
-
if ARGV.empty? || ARGV[0] == 'help'
|
105
|
-
puts opts
|
106
|
-
exit 0
|
107
|
-
end
|
108
|
-
|
109
|
-
command = next_arg "Please specify a command to run"
|
110
|
-
|
111
|
-
if command == "run-as"
|
112
|
-
if username != "admin"
|
113
|
-
$stderr.puts "You don't have permission to do that"
|
114
|
-
exit 1
|
115
|
-
end
|
116
|
-
username = next_arg "Please specify the username to run as"
|
117
|
-
command = next_arg "Please specify a command to run"
|
118
|
-
end
|
119
|
-
|
120
|
-
@username = username
|
121
|
-
|
122
105
|
def implies(a1, a2)
|
123
106
|
case a1
|
124
107
|
when 'admin'
|
@@ -134,8 +117,7 @@ end
|
|
134
117
|
|
135
118
|
def authorize(project_name, action)
|
136
119
|
unless is_authorized(project_name, action)
|
137
|
-
|
138
|
-
exit 3
|
120
|
+
error 3, "You don't have permission to do that"
|
139
121
|
end
|
140
122
|
end
|
141
123
|
|
@@ -204,16 +186,76 @@ def sync_keys
|
|
204
186
|
end
|
205
187
|
end
|
206
188
|
|
207
|
-
|
189
|
+
USERNAME = next_arg "Please specify the username to run as"
|
208
190
|
|
209
|
-
if
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
191
|
+
if ENV['SSH_ORIGINAL_COMMAND']
|
192
|
+
ARGV.clear
|
193
|
+
ENV['SSH_ORIGINAL_COMMAND'].split.each do |arg|
|
194
|
+
ARGV << arg
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def run_command
|
199
|
+
OPTS.parse!
|
200
|
+
@options = DEFAULTS.merge(OPTIONS)
|
201
|
+
@options.freeze
|
202
|
+
|
203
|
+
command = next_arg "Please specify a command to run"
|
204
|
+
|
205
|
+
if command == 'help'
|
206
|
+
puts OPTS
|
207
|
+
puts
|
208
|
+
return 0
|
215
209
|
end
|
210
|
+
|
211
|
+
@username = USERNAME
|
212
|
+
|
213
|
+
if command == "run-as"
|
214
|
+
if USERNAME != "admin"
|
215
|
+
$stderr.puts "You don't have permission to do that"
|
216
|
+
return 1
|
217
|
+
end
|
218
|
+
@username = next_arg "Please specify the username to run as"
|
219
|
+
command = next_arg "Please specify a command to run"
|
220
|
+
end
|
221
|
+
|
222
|
+
command_file = File.expand_path(File.join(File.dirname(__FILE__), "..", "commands", "#{command}.rb"))
|
223
|
+
|
224
|
+
if File.exist?(command_file)
|
225
|
+
begin
|
226
|
+
load command_file
|
227
|
+
rescue SystemCallError => e
|
228
|
+
$stderr.puts "SystemCallError [#{e.errno}]: #{e.message}"
|
229
|
+
return e.errno
|
230
|
+
end
|
231
|
+
else
|
232
|
+
$stderr.puts "Unknown command: #{command}"
|
233
|
+
return 1
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
if ARGV.empty?
|
238
|
+
while true
|
239
|
+
print "hubbard> "
|
240
|
+
line = readline.strip
|
241
|
+
if line == "exit"
|
242
|
+
exit 0
|
243
|
+
else
|
244
|
+
ARGV.clear
|
245
|
+
Shellwords.shellwords(line).each { |arg| ARGV << arg }
|
246
|
+
next if ARGV.empty?
|
247
|
+
begin
|
248
|
+
run_command
|
249
|
+
rescue HubbardException => e
|
250
|
+
$stderr.puts e.message
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
216
254
|
else
|
217
|
-
|
218
|
-
|
255
|
+
begin
|
256
|
+
exit(run_command)
|
257
|
+
rescue HubbardException => e
|
258
|
+
$stderr.puts e.message
|
259
|
+
exit e.exitstatus
|
260
|
+
end
|
219
261
|
end
|
data/commands/add-key.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
name = next_arg("Please specify the key name")
|
2
2
|
if name !~ Hubbard::KEY_NAME_REGEX
|
3
|
-
|
4
|
-
exit 1
|
3
|
+
error 1, "Not a valid key name (letters and numbers only)"
|
5
4
|
end
|
6
5
|
|
7
6
|
key = $stdin.read.strip
|
8
7
|
if key !~ Hubbard::KEY_REGEX
|
9
|
-
|
10
|
-
exit 1
|
8
|
+
error 1, "Not a valid key"
|
11
9
|
end
|
12
10
|
|
13
11
|
type = $1
|
data/commands/add-permission.rb
CHANGED
@@ -5,16 +5,5 @@ username = ARGV.shift
|
|
5
5
|
action = ARGV.shift
|
6
6
|
validate_action_name(action)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
begin
|
11
|
-
filename = File.join(dir, ".permissions")
|
12
|
-
permissions = File.read(filename).split("\n").map { |line| line.strip }.select { |line| line.split('=')[0] != username }
|
13
|
-
permissions << "#{username}=#{action}"
|
14
|
-
File.open(filename, "w") do |file|
|
15
|
-
permissions.each { |permission| file << permission << "\n" }
|
16
|
-
end
|
17
|
-
ensure
|
18
|
-
lock.flock(File::LOCK_UN)
|
19
|
-
end
|
20
|
-
end
|
8
|
+
project = Project.new(project_name)
|
9
|
+
project.lock { project.add_permission(username,action) }
|
data/commands/create-project.rb
CHANGED
@@ -1,18 +1,6 @@
|
|
1
|
-
require 'fileutils'
|
2
|
-
|
3
1
|
project_name = read_project_name
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
10
|
-
unless Dir.mkdir(dir)
|
11
|
-
$stderr.puts "Unable to create directory: #{dir}"
|
12
|
-
end
|
13
|
-
visibility = OPTIONS[:private] ? "private" : "public"
|
14
|
-
if @username != 'admin'
|
15
|
-
File.open(File.join(dir, ".permissions"), "w") { |f| f << "#{@username}=admin\n" }
|
16
|
-
end
|
17
|
-
File.open(File.join(dir, ".visibility"), "w") { |f| f << "#{visibility}\n" }
|
18
|
-
File.open(File.join(dir, ".description"), "w") { |f| f << "#{description}\n" }
|
2
|
+
|
3
|
+
project = Project.new(project_name)
|
4
|
+
project.create
|
5
|
+
project.add_permission(@username,'admin')
|
6
|
+
project.visibility=@options[:private] ? "private" : "public"
|
@@ -4,6 +4,6 @@ authorize(project_name, 'admin')
|
|
4
4
|
dir = find_repository_dir(project_name, repository_name)
|
5
5
|
FileUtils.mkdir_p(dir)
|
6
6
|
Dir.chdir(dir) do
|
7
|
-
|
8
|
-
|
7
|
+
error $?, "Unable to create repository" unless system "git --bare init --shared"
|
8
|
+
error $?, "Unable to create repository" unless system "git config hubbard.forkid #{project_name}/#{repository_name}/#{Time.now.to_i}"
|
9
9
|
end
|
data/commands/fork-repository.rb
CHANGED
@@ -7,9 +7,8 @@ authorize(to_project_name, 'admin')
|
|
7
7
|
from_dir = find_repository_dir(from_project_name, from_repository_name)
|
8
8
|
to_dir = find_repository_dir(to_project_name, to_repository_name)
|
9
9
|
forkid = Dir.chdir(from_dir) { `git config --get hubbard.forkid` }
|
10
|
-
|
11
|
-
exit $? unless system "git clone --bare --shared #{from_dir} #{to_dir}"
|
10
|
+
error $?, "Unable to create repository" unless system "git clone --bare --shared #{from_dir} #{to_dir}"
|
12
11
|
Dir.chdir(to_dir) do
|
13
|
-
|
12
|
+
error $?, "Unable to create repository" unless system "git config hubbard.forkid #{forkid}"
|
14
13
|
end
|
15
14
|
|
data/commands/list-forks.rb
CHANGED
@@ -3,6 +3,7 @@ repository_name = read_repository_name
|
|
3
3
|
authorize(project_name, 'read')
|
4
4
|
forkid = Dir.chdir(find_repository_dir(project_name, repository_name)) { `git config --get hubbard.forkid` }
|
5
5
|
project_dir = find_project_dir(project_name)
|
6
|
+
forks = []
|
6
7
|
Dir.foreach(File.join(Hubbard::PROJECTS_PATH)) do |dir|
|
7
8
|
next if dir == "." || dir == ".."
|
8
9
|
next unless is_authorized(dir, 'read')
|
@@ -11,8 +12,10 @@ Dir.foreach(File.join(Hubbard::PROJECTS_PATH)) do |dir|
|
|
11
12
|
repository_name = repository_dir.chomp('.git')
|
12
13
|
Dir.chdir(find_repository_dir(project_name, repository_name)) do
|
13
14
|
if forkid == `git config --get hubbard.forkid`
|
14
|
-
|
15
|
+
forks << "#{project_name}/#{repository_name}"
|
15
16
|
end
|
16
17
|
end
|
17
18
|
end
|
18
19
|
end
|
20
|
+
|
21
|
+
puts forks.sort
|
data/commands/list-keys.rb
CHANGED
@@ -1,26 +1,13 @@
|
|
1
1
|
project_name = read_project_name
|
2
2
|
authorize(project_name, 'admin')
|
3
|
-
|
4
|
-
username = ARGV.shift
|
3
|
+
project = Project.new(project_name)
|
5
4
|
|
6
|
-
|
7
|
-
permissions_file = File.join(dir, ".permissions")
|
8
|
-
if File.exists?(permissions_file)
|
9
|
-
File.open(permissions_file, "r+") do |f|
|
10
|
-
f.flock(File::LOCK_EX)
|
11
|
-
contents = f.read
|
12
|
-
f.flock(File::LOCK_UN)
|
13
|
-
end
|
14
|
-
end
|
5
|
+
permissions = project.lock { project.permissions }
|
15
6
|
|
16
|
-
if
|
17
|
-
permissions = []
|
18
|
-
contents.split("\n").map do |l|
|
19
|
-
l.strip!
|
20
|
-
p = l.split('=')
|
21
|
-
permissions << { :user => p.first, :access => p.last }
|
22
|
-
end
|
7
|
+
if @options[:format] == :yaml
|
23
8
|
puts YAML::dump(permissions)
|
24
|
-
elsif
|
25
|
-
|
9
|
+
elsif @options[:format] == :text
|
10
|
+
permissions.each do |permission|
|
11
|
+
puts "#{permission[:user]}=#{permission[:access]}"
|
12
|
+
end
|
26
13
|
end
|
data/commands/list-projects.rb
CHANGED
@@ -7,7 +7,7 @@ Dir.foreach(find_project_dir(project_name)) do |repository_dir|
|
|
7
7
|
repositories << { :name => repository_dir.chomp('.git'), :url => git_url }
|
8
8
|
end
|
9
9
|
|
10
|
-
if
|
10
|
+
if @options[:format] == :yaml
|
11
11
|
puts YAML::dump(repositories)
|
12
12
|
else
|
13
13
|
repositories.each { |r| puts "#{r[:name]}\t#{r[:url]}" }
|
data/commands/list-users.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
if @username != 'admin'
|
2
|
-
|
3
|
-
exit 3
|
2
|
+
error 3, "You don't have permission to do that"
|
4
3
|
end
|
5
4
|
|
6
5
|
accounts = []
|
@@ -9,7 +8,9 @@ Dir.entries(Hubbard::ACCOUNTS_PATH).each do |account|
|
|
9
8
|
accounts << account
|
10
9
|
end
|
11
10
|
|
12
|
-
|
11
|
+
accounts.sort!
|
12
|
+
|
13
|
+
if @options[:format] == :yaml
|
13
14
|
puts YAML::dump(accounts)
|
14
15
|
else
|
15
16
|
accounts.each { |a| puts a }
|
data/commands/move-repository.rb
CHANGED
@@ -11,13 +11,11 @@ authorize(from_project_name, 'admin')
|
|
11
11
|
authorize(to_project_name, 'admin')
|
12
12
|
|
13
13
|
if not File.exist?(from_dir)
|
14
|
-
|
15
|
-
exit 4
|
14
|
+
error 4, "Repository not found"
|
16
15
|
end
|
17
16
|
|
18
17
|
if File.exist?(to_dir)
|
19
|
-
|
20
|
-
exit 4
|
18
|
+
error 4, "Repository already exists with that name"
|
21
19
|
end
|
22
20
|
|
23
21
|
FileUtils.mv(from_dir, to_dir)
|
data/commands/remove-key.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
name = next_arg("Please specify the key name")
|
2
2
|
if name !~ Hubbard::KEY_NAME_REGEX
|
3
|
-
|
4
|
-
exit 1
|
3
|
+
error 1, "Not a valid key name (letters and numbers only)"
|
5
4
|
end
|
6
5
|
|
7
6
|
dirname = File.join(find_account_dir(@username), "keys")
|
@@ -9,13 +8,11 @@ FileUtils.mkdir_p(dirname)
|
|
9
8
|
|
10
9
|
filename = File.join(dirname, name)
|
11
10
|
if !File.exist?(filename)
|
12
|
-
|
13
|
-
exit 1
|
11
|
+
error 1, "Key not found"
|
14
12
|
end
|
15
13
|
|
16
14
|
unless FileUtils.rm(filename)
|
17
|
-
|
18
|
-
exit 1
|
15
|
+
error 1, "Unable to delete key"
|
19
16
|
end
|
20
17
|
|
21
18
|
sync_keys
|
@@ -2,15 +2,6 @@ project_name = read_project_name
|
|
2
2
|
authorize(project_name, 'admin')
|
3
3
|
dir = find_project_dir(project_name)
|
4
4
|
username = ARGV.shift
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
filename = File.join(dir, ".permissions")
|
9
|
-
permissions = File.read(filename).split("\n").map { |line| line.strip }.select { |line| line.split('=')[0] != username }
|
10
|
-
File.open(filename, "w") do |file|
|
11
|
-
permissions.each { |permission| file << permission << "\n" }
|
12
|
-
end
|
13
|
-
ensure
|
14
|
-
lock.flock(File::LOCK_UN)
|
15
|
-
end
|
16
|
-
end
|
5
|
+
|
6
|
+
project = Project.new(project_name)
|
7
|
+
project.lock { project.remove_permission(username) }
|
data/commands/rename-project.rb
CHANGED
@@ -3,8 +3,7 @@ to_project_name = next_arg "Please specify the new project name"
|
|
3
3
|
from_dir = find_project_dir(from_project_name)
|
4
4
|
to_dir = find_project_dir(to_project_name)
|
5
5
|
if File.exist?(to_dir)
|
6
|
-
|
7
|
-
exit 3
|
6
|
+
error 3, "A project already exists with that name"
|
8
7
|
end
|
9
8
|
|
10
9
|
authorize(from_project_name, 'admin')
|
data/commands/set-description.rb
CHANGED
@@ -3,13 +3,13 @@ require 'fileutils'
|
|
3
3
|
project_name = read_project_name
|
4
4
|
authorize(project_name, 'admin')
|
5
5
|
|
6
|
-
description =
|
6
|
+
description = rest_args "Please specify the description"
|
7
|
+
desc = description.join(' ')
|
7
8
|
|
8
9
|
dir = find_project_dir(project_name)
|
9
10
|
if !File.exist?(dir)
|
10
|
-
|
11
|
-
exit 4
|
11
|
+
error 4, "Project not found"
|
12
12
|
end
|
13
13
|
|
14
|
-
File.open(File.join(dir, ".description"), "w") { |f| f <<
|
14
|
+
File.open(File.join(dir, ".description"), "w") { |f| f << desc << "\n" }
|
15
15
|
|
data/commands/set-visibility.rb
CHANGED
@@ -3,14 +3,12 @@ require 'fileutils'
|
|
3
3
|
project_name = read_project_name
|
4
4
|
visibility = next_arg "Please specify one of: public, private"
|
5
5
|
if visibility != 'public' and visibility != 'private'
|
6
|
-
|
7
|
-
exit 3
|
6
|
+
error 3, "Please specify one of: public, private"
|
8
7
|
end
|
9
8
|
|
10
9
|
dir = find_project_dir(project_name)
|
11
10
|
if !File.exist?(dir)
|
12
|
-
|
13
|
-
exit 4
|
11
|
+
error 4, "Project not found"
|
14
12
|
end
|
15
13
|
|
16
14
|
File.open(File.join(dir, ".visibility"), "w") { |f| f << visibility << "\n" }
|
data/hubbard.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{hubbard}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.18"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matthew Foemmel"]
|
12
|
-
s.date = %q{2010-03-
|
12
|
+
s.date = %q{2010-03-25}
|
13
13
|
s.default_executable = %q{hubbard}
|
14
14
|
s.description = %q{Hubbard is a command line tool for managing git repositories.}
|
15
15
|
s.email = %q{git@foemmel.com}
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"README.md",
|
26
26
|
"Rakefile",
|
27
27
|
"VERSION",
|
28
|
+
"bin/hub-daemon",
|
28
29
|
"bin/hubbard",
|
29
30
|
"commands/add-key.rb",
|
30
31
|
"commands/add-permission.rb",
|
@@ -49,6 +50,7 @@ Gem::Specification.new do |s|
|
|
49
50
|
"commands/whoami.rb",
|
50
51
|
"hubbard.gemspec",
|
51
52
|
"lib/hubbard.rb",
|
53
|
+
"lib/project.rb",
|
52
54
|
"spec/gitssh",
|
53
55
|
"spec/hubbard_spec.rb",
|
54
56
|
"spec/spec.opts",
|
@@ -58,12 +60,12 @@ Gem::Specification.new do |s|
|
|
58
60
|
s.homepage = %q{http://github.com/mfoemmel/hubbard}
|
59
61
|
s.rdoc_options = ["--charset=UTF-8"]
|
60
62
|
s.require_paths = ["lib"]
|
61
|
-
s.rubygems_version = %q{1.3.
|
63
|
+
s.rubygems_version = %q{1.3.6}
|
62
64
|
s.summary = %q{Hubbard is a command line tool for managing git repositories.}
|
63
65
|
s.test_files = [
|
64
|
-
"spec/
|
65
|
-
"spec/
|
66
|
-
"spec/
|
66
|
+
"spec/hubbard_spec.rb",
|
67
|
+
"spec/spec_helper.rb",
|
68
|
+
"spec/yaml_spec.rb"
|
67
69
|
]
|
68
70
|
|
69
71
|
if s.respond_to? :specification_version then
|
data/lib/project.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class Project
|
2
|
+
attr_reader :project_name
|
3
|
+
|
4
|
+
def initialize(project_name)
|
5
|
+
@project_name = project_name
|
6
|
+
@dir = find_project_dir project_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def create
|
10
|
+
if File.exist?(@dir)
|
11
|
+
error 4, "Project already exists with that name"
|
12
|
+
end
|
13
|
+
|
14
|
+
unless Dir.mkdir(@dir)
|
15
|
+
error 1, "Unable to create directory: #{dir}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def lock
|
20
|
+
File.open(File.join(@dir, ".lock"), "w+") do |lock|
|
21
|
+
lock.flock(File::LOCK_EX)
|
22
|
+
begin
|
23
|
+
yield
|
24
|
+
ensure
|
25
|
+
lock.flock(File::LOCK_UN)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def visibility=(visibility)
|
31
|
+
File.open(File.join(@dir, ".visibility"), "w") { |f| f << "#{visibility}\n" }
|
32
|
+
end
|
33
|
+
|
34
|
+
def description=(description)
|
35
|
+
File.open(File.join(@dir, ".description"), "w") { |f| f << "#{description}\n" }
|
36
|
+
end
|
37
|
+
|
38
|
+
def permissions
|
39
|
+
if File.exists?(permissions_file)
|
40
|
+
File.read(permissions_file).split("\n").map do |line|
|
41
|
+
permission = line.strip.split('=')
|
42
|
+
{ :user => permission.first, :access => permission.last }
|
43
|
+
end
|
44
|
+
else
|
45
|
+
[]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_permission(username,action)
|
50
|
+
new_permissions = permissions.select { |permission| permission[:user] != username }
|
51
|
+
if username != 'admin'
|
52
|
+
new_permissions << { :user => username, :access => action }
|
53
|
+
end
|
54
|
+
File.open(permissions_file, "w") do |file|
|
55
|
+
new_permissions.each { |permission| file << permission[:user] << '=' << permission[:access] << "\n" }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def remove_permission(username)
|
60
|
+
new_permissions = permissions.select { |permission| permission[:user] != username }
|
61
|
+
File.open(permissions_file, "w") do |file|
|
62
|
+
new_permissions.each { |permission| file << permission[:user] << '=' << permission[:access] << "\n" }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def permissions_file
|
69
|
+
File.join(@dir, ".permissions")
|
70
|
+
end
|
71
|
+
end
|
data/spec/hubbard_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
|
-
describe "
|
4
|
+
describe "Hubbard" do
|
5
5
|
before(:each) do
|
6
6
|
reset_file_system
|
7
7
|
end
|
@@ -14,40 +14,44 @@ describe "Hubble" do
|
|
14
14
|
pending "Not sure how to make sure that hubbard is passing back the proper exit codes from SystemCallErrors. Doing so would introduce complexity or add something that shouldn't be callable."
|
15
15
|
end
|
16
16
|
|
17
|
-
it "should create project" do
|
18
|
-
hub("kipper", "create-project foo
|
17
|
+
it "should create project and set project description" do
|
18
|
+
hub("kipper", "create-project foo")
|
19
|
+
hub("kipper", "set-description foo foo-desc")
|
19
20
|
projects = list_projects('kipper')
|
20
21
|
projects.should == ["foo"]
|
21
22
|
end
|
22
23
|
|
23
24
|
it "should set project description" do
|
24
|
-
hub("kipper", "create-project foo
|
25
|
-
hub("kipper", "set-description foo
|
25
|
+
hub("kipper", "create-project foo")
|
26
|
+
hub("kipper", "set-description foo 'Test description contains a space.'")
|
26
27
|
project = hub("kipper", "list-projects").split("\n")[0].split
|
27
|
-
project
|
28
|
+
project_name = project.shift # throw away unused arg.
|
29
|
+
visibility = project.shift # throw away unused arg.
|
30
|
+
description = project.join(' ')
|
31
|
+
description.should == "Test description contains a space."
|
28
32
|
end
|
29
33
|
|
30
34
|
it "should set project visibility" do
|
31
|
-
|
35
|
+
create_project("kipper", "foo", "foo-desc")
|
32
36
|
hub("kipper", "set-visibility foo private")
|
33
37
|
project = hub("kipper", "list-projects").split("\n")[0].split
|
34
38
|
project[1].should == "private"
|
35
39
|
end
|
36
40
|
|
37
41
|
it "should rename project" do
|
38
|
-
|
42
|
+
create_project("kipper", "foo", "foo-desc")
|
39
43
|
hub("kipper", "rename-project foo bar")
|
40
44
|
project = hub("kipper", "list-projects").split("\n")[0].split
|
41
45
|
project[0].should == "bar"
|
42
46
|
end
|
43
47
|
|
44
48
|
it "should not allow multiple projects with same name" do
|
45
|
-
|
49
|
+
create_project("kipper", "foo", "foo-desc")
|
46
50
|
lambda { hub("kipper", "create-project foo") }.should raise_error
|
47
51
|
end
|
48
52
|
|
49
53
|
it "should delete project" do
|
50
|
-
|
54
|
+
create_project("kipper", "foo", "foo-desc")
|
51
55
|
hub("kipper", "delete-project foo")
|
52
56
|
|
53
57
|
projects = hub("kipper", "list-projects").split("\n")
|
@@ -55,7 +59,7 @@ describe "Hubble" do
|
|
55
59
|
end
|
56
60
|
|
57
61
|
it "should default to public project" do
|
58
|
-
|
62
|
+
create_project("kipper", "foo", "foo-desc")
|
59
63
|
|
60
64
|
# Other users can see...
|
61
65
|
projects = list_projects("tiger")
|
@@ -66,7 +70,8 @@ describe "Hubble" do
|
|
66
70
|
end
|
67
71
|
|
68
72
|
it "should support private project" do
|
69
|
-
hub("kipper", "create-project foo
|
73
|
+
hub("kipper", "create-project foo --private")
|
74
|
+
hub("kipper", "set-description foo new-desc")
|
70
75
|
|
71
76
|
# Other users can't see
|
72
77
|
projects = hub("tiger", "list-projects").split("\n")
|
@@ -74,7 +79,7 @@ describe "Hubble" do
|
|
74
79
|
end
|
75
80
|
|
76
81
|
it "should create repositories" do
|
77
|
-
|
82
|
+
create_project("kipper", "foo", "foo-desc")
|
78
83
|
hub("kipper", "create-repository foo bar")
|
79
84
|
|
80
85
|
repositories = hub("kipper", "list-repositories foo").split("\n")
|
@@ -86,7 +91,7 @@ describe "Hubble" do
|
|
86
91
|
|
87
92
|
describe "when admin creates a project" do
|
88
93
|
before(:each) do
|
89
|
-
|
94
|
+
create_project("admin", "foo", "foo-desc")
|
90
95
|
end
|
91
96
|
|
92
97
|
it "should not raise error on missing permissions file for non-admin listing permissions" do
|
@@ -111,7 +116,7 @@ describe "Hubble" do
|
|
111
116
|
end
|
112
117
|
|
113
118
|
it "should allow git push" do
|
114
|
-
|
119
|
+
create_project("kipper", "foo", "foo-desc")
|
115
120
|
hub("kipper", "create-repository foo bar")
|
116
121
|
|
117
122
|
with_test_project do
|
@@ -120,8 +125,8 @@ describe "Hubble" do
|
|
120
125
|
end
|
121
126
|
|
122
127
|
it "should move repository" do
|
123
|
-
|
124
|
-
|
128
|
+
create_project("kipper", "foo", "foo-desc")
|
129
|
+
create_project("kipper", "new-foo", "foo-desc")
|
125
130
|
hub("kipper", "create-repository foo bar")
|
126
131
|
|
127
132
|
with_test_project do
|
@@ -132,7 +137,7 @@ describe "Hubble" do
|
|
132
137
|
end
|
133
138
|
|
134
139
|
it "should allow git push with write permissions" do
|
135
|
-
|
140
|
+
create_project("kipper", "foo", "foo-desc")
|
136
141
|
hub("kipper", "add-permission foo tiger write")
|
137
142
|
hub("kipper", "create-repository foo bar")
|
138
143
|
|
@@ -142,7 +147,7 @@ describe "Hubble" do
|
|
142
147
|
end
|
143
148
|
|
144
149
|
it "should not allow git push with read permissions" do
|
145
|
-
|
150
|
+
create_project("kipper", "foo", "foo-desc")
|
146
151
|
hub("kipper", "add-permission foo tiger read")
|
147
152
|
hub("kipper", "create-repository foo bar")
|
148
153
|
|
@@ -152,7 +157,7 @@ describe "Hubble" do
|
|
152
157
|
end
|
153
158
|
|
154
159
|
it "should allow git pull" do
|
155
|
-
|
160
|
+
create_project("kipper", "foo", "foo-desc")
|
156
161
|
hub("kipper", "create-repository foo bar")
|
157
162
|
|
158
163
|
with_test_project do
|
@@ -162,7 +167,8 @@ describe "Hubble" do
|
|
162
167
|
end
|
163
168
|
|
164
169
|
it "should not allow git pull with no permissions" do
|
165
|
-
hub("kipper", "create-project foo
|
170
|
+
hub("kipper", "create-project foo --private")
|
171
|
+
hub("kipper", "set-description foo foo-desc")
|
166
172
|
hub("kipper", "create-repository foo bar")
|
167
173
|
|
168
174
|
with_test_project do
|
@@ -182,7 +188,7 @@ describe "Hubble" do
|
|
182
188
|
end
|
183
189
|
|
184
190
|
it "should fork repository in same project" do
|
185
|
-
|
191
|
+
create_project("kipper", "foo", "foo-desc")
|
186
192
|
hub("kipper", "create-repository foo bar")
|
187
193
|
|
188
194
|
with_test_project do
|
@@ -193,8 +199,8 @@ describe "Hubble" do
|
|
193
199
|
end
|
194
200
|
|
195
201
|
it "should fork repository in different project" do
|
196
|
-
|
197
|
-
|
202
|
+
create_project("kipper", "foo", "foo-desc")
|
203
|
+
create_project("kipper", "foo2", "foo2-desc")
|
198
204
|
hub("kipper", "create-repository foo bar")
|
199
205
|
|
200
206
|
with_test_project do
|
@@ -205,7 +211,7 @@ describe "Hubble" do
|
|
205
211
|
end
|
206
212
|
|
207
213
|
it "should track projects related by forking" do
|
208
|
-
|
214
|
+
create_project("kipper", "foo", "foo-desc")
|
209
215
|
hub("kipper", "create-repository foo bar")
|
210
216
|
|
211
217
|
with_test_project do
|
@@ -216,8 +222,8 @@ describe "Hubble" do
|
|
216
222
|
end
|
217
223
|
|
218
224
|
it "should require read access to fork repository" do
|
219
|
-
|
220
|
-
|
225
|
+
create_project("kipper", "foo", "foo-desc")
|
226
|
+
create_project("kipper", "foo2", "foo2-desc")
|
221
227
|
hub("kipper", "create-repository foo bar")
|
222
228
|
|
223
229
|
with_test_project do
|
@@ -234,7 +240,7 @@ describe "Hubble" do
|
|
234
240
|
end
|
235
241
|
|
236
242
|
it "should remove permission" do
|
237
|
-
|
243
|
+
create_project("kipper", "foo", "foo-desc")
|
238
244
|
hub("kipper", "create-repository foo bar")
|
239
245
|
hub("kipper", "add-permission foo tiger read")
|
240
246
|
hub("kipper", "remove-permission foo tiger")
|
@@ -261,7 +267,8 @@ describe "Hubble" do
|
|
261
267
|
end
|
262
268
|
|
263
269
|
it "should allow admin to run-as another user" do
|
264
|
-
hub("admin", "run-as kipper create-project foo
|
270
|
+
hub("admin", "run-as kipper create-project foo")
|
271
|
+
hub("admin", "run-as kipper set-description foo foo-desc")
|
265
272
|
projects = list_projects("kipper")
|
266
273
|
projects.should == ["foo"]
|
267
274
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -42,6 +42,12 @@ def reset_file_system
|
|
42
42
|
FileUtils.rm_rf "tmp"
|
43
43
|
end
|
44
44
|
|
45
|
+
# Simple helper to create a public project with a description.
|
46
|
+
def create_project(user, project_name, project_desc)
|
47
|
+
hub(user, "create-project #{project_name}")
|
48
|
+
hub(user, "set-description #{project_name} #{project_desc}")
|
49
|
+
end
|
50
|
+
|
45
51
|
def list_projects(user)
|
46
52
|
hub(user, "list-projects").split("\n").map { |line| line.split[0] }
|
47
53
|
end
|
data/spec/yaml_spec.rb
CHANGED
@@ -12,16 +12,16 @@ describe "Hubble with yaml output" do
|
|
12
12
|
end
|
13
13
|
|
14
14
|
it "should list-projects" do
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
create_project("yammer", "a", "a-desc")
|
16
|
+
create_project("yammer", "b", "b-desc")
|
17
|
+
create_project("yammer", "c", "c-desc")
|
18
18
|
|
19
19
|
projects = YAML::load(hub("yammer", "#{YAML_OPTION} list-projects")).map{|project|project[:name]}
|
20
20
|
projects.should == ["a", "b", "c"]
|
21
21
|
end
|
22
22
|
|
23
23
|
it "should list repositories" do
|
24
|
-
|
24
|
+
create_project("yammer", "a", "a-desc")
|
25
25
|
hub("yammer", "create-repository a b")
|
26
26
|
|
27
27
|
repositories = YAML::load(hub("yammer", "#{YAML_OPTION} list-repositories a"))
|
@@ -31,7 +31,7 @@ describe "Hubble with yaml output" do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
it "should list permissions" do
|
34
|
-
|
34
|
+
create_project("yammer", "a", "a-desc")
|
35
35
|
permissions = YAML::load(hub("yammer", "#{YAML_OPTION} list-permissions a"))
|
36
36
|
permissions.length.should == 1
|
37
37
|
permissions.first[:user].should == "yammer"
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hubbard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 18
|
9
|
+
version: 0.0.18
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Matthew Foemmel
|
@@ -9,19 +14,23 @@ autorequire:
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-25 00:00:00 -05:00
|
13
18
|
default_executable: hubbard
|
14
19
|
dependencies:
|
15
20
|
- !ruby/object:Gem::Dependency
|
16
21
|
name: rspec
|
17
|
-
|
18
|
-
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
24
|
requirements:
|
21
25
|
- - ">="
|
22
26
|
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 2
|
30
|
+
- 9
|
23
31
|
version: 1.2.9
|
24
|
-
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
25
34
|
description: Hubbard is a command line tool for managing git repositories.
|
26
35
|
email: git@foemmel.com
|
27
36
|
executables:
|
@@ -38,6 +47,7 @@ files:
|
|
38
47
|
- README.md
|
39
48
|
- Rakefile
|
40
49
|
- VERSION
|
50
|
+
- bin/hub-daemon
|
41
51
|
- bin/hubbard
|
42
52
|
- commands/add-key.rb
|
43
53
|
- commands/add-permission.rb
|
@@ -62,6 +72,7 @@ files:
|
|
62
72
|
- commands/whoami.rb
|
63
73
|
- hubbard.gemspec
|
64
74
|
- lib/hubbard.rb
|
75
|
+
- lib/project.rb
|
65
76
|
- spec/gitssh
|
66
77
|
- spec/hubbard_spec.rb
|
67
78
|
- spec/spec.opts
|
@@ -80,22 +91,24 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
80
91
|
requirements:
|
81
92
|
- - ">="
|
82
93
|
- !ruby/object:Gem::Version
|
94
|
+
segments:
|
95
|
+
- 0
|
83
96
|
version: "0"
|
84
|
-
version:
|
85
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
98
|
requirements:
|
87
99
|
- - ">="
|
88
100
|
- !ruby/object:Gem::Version
|
101
|
+
segments:
|
102
|
+
- 0
|
89
103
|
version: "0"
|
90
|
-
version:
|
91
104
|
requirements: []
|
92
105
|
|
93
106
|
rubyforge_project:
|
94
|
-
rubygems_version: 1.3.
|
107
|
+
rubygems_version: 1.3.6
|
95
108
|
signing_key:
|
96
109
|
specification_version: 3
|
97
110
|
summary: Hubbard is a command line tool for managing git repositories.
|
98
111
|
test_files:
|
99
|
-
- spec/yaml_spec.rb
|
100
112
|
- spec/hubbard_spec.rb
|
101
113
|
- spec/spec_helper.rb
|
114
|
+
- spec/yaml_spec.rb
|