shagit 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +29 -0
- data/LICENSE +21 -0
- data/README.md +58 -0
- data/VERSION.yml +5 -0
- data/bin/shagit +11 -0
- data/config.ru +3 -0
- data/config.yml +6 -0
- data/lib/authorization.rb +33 -0
- data/lib/config_info.rb +9 -0
- data/lib/enhancing_grit.rb +29 -0
- data/lib/helpers/helpers.rb +115 -0
- data/lib/shagit.rb +60 -0
- data/public/buttons.css +82 -0
- data/public/reset.css +7 -0
- data/public/shagit.css +354 -0
- data/rakefile +99 -0
- data/shagit_app.rb +137 -0
- data/test/acceptance/acceptance_test.rb +86 -0
- data/test/unit/shagit_test.rb +49 -0
- data/views/delete.haml +13 -0
- data/views/delete_confirmation.haml +6 -0
- data/views/index.haml +14 -0
- data/views/layout.haml +17 -0
- data/views/login.haml +15 -0
- data/views/login_failed.haml +15 -0
- data/views/logout.haml +9 -0
- data/views/new.haml +10 -0
- data/views/new_confirmation.haml +6 -0
- data/views/repo.haml +41 -0
- metadata +160 -0
data/CHANGES
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
0.3 (2010-03-17)
|
2
|
+
==================================
|
3
|
+
* refactored global variables into a singleton class
|
4
|
+
* changed require statement inside config.ru to reflect recent name changes
|
5
|
+
* modified stylesheet
|
6
|
+
* exchanged OS call 'hostname' with request.env
|
7
|
+
* fixed repository location bug
|
8
|
+
* added rakefile
|
9
|
+
* added proper dependencies for production & development to gem
|
10
|
+
* added new test case to unit test (tests loading of the configuration file)
|
11
|
+
* added gem building using jeweler
|
12
|
+
* added runtime checking (to check if Shagit was installed using the gem)
|
13
|
+
|
14
|
+
0.2 (2010-02-27)
|
15
|
+
==================================
|
16
|
+
* fixed password input field
|
17
|
+
* implemented working_dir setting
|
18
|
+
* converted README to Markdown format
|
19
|
+
* moved helpers folder to lib
|
20
|
+
* added $LOAD_PATH statements
|
21
|
+
* renamed shagit.rb to shagit_app.rb due to name conflicts with lib/shagit.rb
|
22
|
+
* added acceptance tests using Webrat
|
23
|
+
|
24
|
+
0.1 Initial Release (2010-01-11)
|
25
|
+
==================================
|
26
|
+
* Basic create, optimize and delete functions implemented for repositories
|
27
|
+
* Authentication system implemented
|
28
|
+
* Integration of Integrity's CSS and layout
|
29
|
+
* Deployment via Phusion Passenger
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009, 2010 Martin Gajdos
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
Shagit
|
2
|
+
============
|
3
|
+
|
4
|
+
Description: A simple web application for local, private git repository management written in Sinatra
|
5
|
+
Copyright (c) 2009, 2010 Martin Gajdos
|
6
|
+
|
7
|
+
released under the MIT license
|
8
|
+
|
9
|
+
Introduction
|
10
|
+
------------
|
11
|
+
|
12
|
+
Shagit is a simple web application for managing your local git repositories. There's no need for a database and repositories are being privately published using ssh.
|
13
|
+
|
14
|
+
Dependencies
|
15
|
+
------------
|
16
|
+
|
17
|
+
* Sinatra
|
18
|
+
* Haml
|
19
|
+
* Grit
|
20
|
+
* Rack-Test
|
21
|
+
* Webrat
|
22
|
+
|
23
|
+
Installation
|
24
|
+
------------
|
25
|
+
|
26
|
+
You will need a working installation of Ruby >=1.8.6, RubyGems >= 1.3.5 and Git >= 1.5
|
27
|
+
|
28
|
+
Clone the repository:
|
29
|
+
|
30
|
+
git clone git://github.com/unabatede/shagit.git
|
31
|
+
|
32
|
+
Install the Sinatra, Haml & Grit gems:
|
33
|
+
|
34
|
+
gem install sinatra haml grit rack-test webrat
|
35
|
+
|
36
|
+
Run it (you should consider other options for production deployment):
|
37
|
+
|
38
|
+
cd shagit
|
39
|
+
ruby shagit.rb -e production
|
40
|
+
|
41
|
+
Deployment
|
42
|
+
----------
|
43
|
+
|
44
|
+
Using Apache & Phusion Passenger and the following to a new virtual host file (adjust to suite your needs):
|
45
|
+
|
46
|
+
<VirtualHost *:80>
|
47
|
+
DocumentRoot /var/www/shagit/public
|
48
|
+
<Directory /var/www/shagit/public>
|
49
|
+
Allow from all
|
50
|
+
Options -MultiViews
|
51
|
+
</Directory>
|
52
|
+
</VirtualHost>
|
53
|
+
|
54
|
+
|
55
|
+
Also, inside Shagit's folder, create a 'tmp' and 'public' folder:
|
56
|
+
|
57
|
+
cd /var/www/shagit
|
58
|
+
mkdir tmp; mkdir public
|
data/bin/shagit
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..')
|
3
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'sinatra'
|
7
|
+
require 'shagit_app'
|
8
|
+
|
9
|
+
set :environment, :production
|
10
|
+
|
11
|
+
Sinatra::Application.run!
|
data/config.ru
ADDED
data/config.yml
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Authorization
|
3
|
+
|
4
|
+
def authorize!(username, password)
|
5
|
+
# get the only instance of the Config class
|
6
|
+
config_data = ConfigInfo.instance
|
7
|
+
|
8
|
+
if (username == config_data.username) && (password == config_data.password)
|
9
|
+
session[:authorized] = true
|
10
|
+
true
|
11
|
+
else
|
12
|
+
session[:authorized] = false
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def is_authorized?
|
19
|
+
if session[:authorized]
|
20
|
+
true
|
21
|
+
else
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def requires_login!
|
27
|
+
if !is_authorized?
|
28
|
+
redirect '/login'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/config_info.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# this adds a method called 'repo_name' that returns only the filename without path or file extension
|
2
|
+
require 'pathname'
|
3
|
+
require 'find'
|
4
|
+
|
5
|
+
module Grit
|
6
|
+
# return foldername including extension
|
7
|
+
def shagit_foldername
|
8
|
+
foldername = Pathname.new(self.path).basename.to_s
|
9
|
+
end
|
10
|
+
|
11
|
+
# return foldername from path without extension
|
12
|
+
def shagit_name
|
13
|
+
foldername = Pathname.new(self.shagit_foldername).basename.to_s
|
14
|
+
|
15
|
+
# extract repository name without .git extension
|
16
|
+
repo_name = foldername.match(/^[\w\s]+/).to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
# return size of folder containing the repository in Kilobytes
|
20
|
+
def shagit_size
|
21
|
+
dirsize = 0
|
22
|
+
# recursively search the repositories path and sum up all file sizes
|
23
|
+
Find.find(self.path) do |file|
|
24
|
+
dirsize += File.stat(file).size
|
25
|
+
end
|
26
|
+
|
27
|
+
dirsize
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "../"))
|
2
|
+
|
3
|
+
require 'authorization'
|
4
|
+
require 'pathname'
|
5
|
+
require 'config_info'
|
6
|
+
|
7
|
+
include Sinatra::Authorization
|
8
|
+
|
9
|
+
def stylesheets(*sheets)
|
10
|
+
sheets.each { |sheet|
|
11
|
+
haml_tag(:link, :href => "/#{sheet}.css", :type => "text/css", :rel => "stylesheet")
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def cycle(*values)
|
16
|
+
@cycles ||= {}
|
17
|
+
@cycles[values] ||= -1 # first value returned is 0
|
18
|
+
next_value = @cycles[values] = (@cycles[values] + 1) % values.size
|
19
|
+
values[next_value]
|
20
|
+
end
|
21
|
+
|
22
|
+
def full_path
|
23
|
+
# get the only instance of the Config class
|
24
|
+
config_data = ConfigInfo.instance
|
25
|
+
#hostname = `hostname`
|
26
|
+
hostname = request.env['SERVER_NAME']
|
27
|
+
if (config_data.working_dir == '.')
|
28
|
+
full_path = "/#{@current_repo.shagit_foldername}"
|
29
|
+
else
|
30
|
+
full_path = "#{config_data.working_dir}/#{@current_repo.shagit_foldername}"
|
31
|
+
end
|
32
|
+
|
33
|
+
"ssh://#{reformat_string(hostname)}#{reformat_string(full_path)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def reformat_string(source)
|
37
|
+
source.strip
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_config_file_dir(dir)
|
41
|
+
# check whether this is being called from a webrat test and if yes, adjust the calling path for the config_data file
|
42
|
+
if dir[/[\w]+$/] == "helpers"
|
43
|
+
dir = Pathname.new(File.expand_path(File.dirname(__FILE__)))
|
44
|
+
dir.parent.parent
|
45
|
+
else
|
46
|
+
dir
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_config(file)
|
51
|
+
current_dir = File.expand_path(File.dirname(__FILE__))
|
52
|
+
absolute_filepath = File.join(get_config_file_dir(current_dir), file)
|
53
|
+
|
54
|
+
if File.exist?(absolute_filepath)
|
55
|
+
config_data = ConfigInfo.instance
|
56
|
+
|
57
|
+
yaml = YAML.load_file(absolute_filepath)
|
58
|
+
config_data.username = yaml['username']
|
59
|
+
config_data.password = yaml['password']
|
60
|
+
|
61
|
+
working_dir = yaml['working_dir']
|
62
|
+
|
63
|
+
# check whether working_dir has been specified
|
64
|
+
unless (working_dir == nil) || (working_dir.empty?)
|
65
|
+
working_dir = working_dir.strip
|
66
|
+
# check whether the specified folder exists, if not, set it to the directory Shagit's located at
|
67
|
+
if FileTest.directory?(working_dir)
|
68
|
+
config_data.working_dir = working_dir
|
69
|
+
else
|
70
|
+
set_working_dir_to_current_dir
|
71
|
+
end
|
72
|
+
else
|
73
|
+
set_working_dir_to_current_dir
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def set_working_dir_to_current_dir
|
79
|
+
config_data = ConfigInfo.instance
|
80
|
+
config_data.working_dir = "."
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_fullpath(path)
|
84
|
+
config_data = ConfigInfo.instance
|
85
|
+
|
86
|
+
# add the .git extension if it isn't there already
|
87
|
+
if !path.include?('.git')
|
88
|
+
path = "#{path}.git"
|
89
|
+
end
|
90
|
+
|
91
|
+
fullpath = "#{config_data.working_dir}/#{path}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def check_if_started_from_gem(current_working_directory)
|
95
|
+
config_data = ConfigInfo.instance
|
96
|
+
|
97
|
+
# check if the bin folder is included in the directory this file is located in
|
98
|
+
if current_working_directory.include?('bin')
|
99
|
+
if (config_data.working_dir == '.')
|
100
|
+
puts "FATAL ERROR: The directory for saving repositories cannot be used!"
|
101
|
+
puts "Please set the path in your config.yml accordingly."
|
102
|
+
exit
|
103
|
+
end
|
104
|
+
|
105
|
+
# if so, we know Shagit has been installed via gem and the application's root folder has to be redirected
|
106
|
+
set :root, current_working_directory
|
107
|
+
end
|
108
|
+
|
109
|
+
# check if the working directory for saving repositories is writable
|
110
|
+
if !FileTest.writable_real?(config_data.working_dir)
|
111
|
+
puts "FATAL ERROR: The directory for saving repositories (#{config_data.working_dir}) is not writable!"
|
112
|
+
puts "Please adjust your config.yml accordingly."
|
113
|
+
exit
|
114
|
+
end
|
115
|
+
end
|
data/lib/shagit.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'grit'
|
4
|
+
require 'config_info'
|
5
|
+
include Grit
|
6
|
+
|
7
|
+
# Main class for shagit, initializes and manages all repositories
|
8
|
+
class Shagit
|
9
|
+
attr_reader :repositories
|
10
|
+
|
11
|
+
# checks if a specified directory is a github repository
|
12
|
+
def self.is_it_a_git_repo?(path)
|
13
|
+
if FileTest.directory?(path) && FileTest.directory?("#{path}/hooks") && FileTest.directory?("#{path}/info") && FileTest.directory?("#{path}/objects") && FileTest.directory?("#{path}/refs")
|
14
|
+
true
|
15
|
+
else
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# initialize shagit by looking for git repositories in specified path
|
21
|
+
def initialize
|
22
|
+
# get the only instance of the Config class
|
23
|
+
config_data = ConfigInfo.instance
|
24
|
+
|
25
|
+
@repositories = Array.new
|
26
|
+
Dir.foreach(config_data.working_dir) do |path|
|
27
|
+
fullpath = "#{config_data.working_dir}/#{path}"
|
28
|
+
|
29
|
+
if Shagit.is_it_a_git_repo?(fullpath)
|
30
|
+
puts "adding repository: #{fullpath}"
|
31
|
+
# create a new Grit repository object if a directory has been found that looks to be a folder containing a git repository
|
32
|
+
@repositories << Repo.new(fullpath) unless (path == '.git')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# creates a new bare repository for the specified path if it doesn't already exist
|
38
|
+
def self.create_repo(full_repo_name)
|
39
|
+
# if the repository already exists, simply return 'false'
|
40
|
+
if FileTest.directory?(full_repo_name)
|
41
|
+
false
|
42
|
+
else
|
43
|
+
puts "creating bare repository at: #{full_repo_name}"
|
44
|
+
#new_repo = Grit::Repo.init_bare(full_repo_name)
|
45
|
+
puts "pwd: #{Dir.pwd}"
|
46
|
+
new_repo = Grit::Repo.init_bare(full_repo_name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# deletes an existing repository
|
51
|
+
def self.delete_repo!(full_repo_name)
|
52
|
+
if FileTest.directory?(full_repo_name)
|
53
|
+
FileUtils.rm_rf(full_repo_name)
|
54
|
+
true
|
55
|
+
else
|
56
|
+
false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
data/public/buttons.css
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
/* --------------------------------------------------------------
|
2
|
+
|
3
|
+
buttons.css
|
4
|
+
* Gives you some great CSS-only buttons.
|
5
|
+
|
6
|
+
Created by Kevin Hale [particletree.com]
|
7
|
+
* particletree.com/features/rediscovering-the-button-element
|
8
|
+
|
9
|
+
See Readme.txt in this folder for instructions.
|
10
|
+
|
11
|
+
-------------------------------------------------------------- */
|
12
|
+
|
13
|
+
button {
|
14
|
+
display:block;
|
15
|
+
float:left;
|
16
|
+
margin:0 0.583em 0.667em 0;
|
17
|
+
padding:5px 10px 5px 7px; /* Links */
|
18
|
+
|
19
|
+
border:1px solid #dedede;
|
20
|
+
border-top:1px solid #eee;
|
21
|
+
border-left:1px solid #eee;
|
22
|
+
|
23
|
+
background-color:#f5f5f5;
|
24
|
+
font-family:"Lucida Grande", Tahoma, Arial, Verdana, sans-serif;
|
25
|
+
font-size:100%;
|
26
|
+
line-height:130%;
|
27
|
+
text-decoration:none;
|
28
|
+
font-weight:bold;
|
29
|
+
color:#565656;
|
30
|
+
cursor:pointer;
|
31
|
+
}
|
32
|
+
button {
|
33
|
+
width:auto;
|
34
|
+
overflow:visible;
|
35
|
+
padding:4px 10px 3px 7px; /* IE6 */
|
36
|
+
}
|
37
|
+
button[type] {
|
38
|
+
padding:4px 10px 4px 7px; /* Firefox */
|
39
|
+
line-height:17px; /* Safari */
|
40
|
+
}
|
41
|
+
*:first-child+html button[type] {
|
42
|
+
padding:4px 10px 3px 7px; /* IE7 */
|
43
|
+
}
|
44
|
+
button img {
|
45
|
+
margin:0 3px -3px 0 !important;
|
46
|
+
padding:0;
|
47
|
+
border:none;
|
48
|
+
width:16px;
|
49
|
+
height:16px;
|
50
|
+
float:none;
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
/* Button colors
|
55
|
+
-------------------------------------------------------------- */
|
56
|
+
|
57
|
+
/* Standard */
|
58
|
+
button:hover {
|
59
|
+
background-color:#dff4ff;
|
60
|
+
border:1px solid #c2e1ef;
|
61
|
+
color:#336699;
|
62
|
+
}
|
63
|
+
|
64
|
+
/* Positive */
|
65
|
+
body .positive {
|
66
|
+
color:#529214;
|
67
|
+
}
|
68
|
+
button.positive:hover {
|
69
|
+
background-color:#E6EFC2;
|
70
|
+
border:1px solid #C6D880;
|
71
|
+
color:#529214;
|
72
|
+
}
|
73
|
+
|
74
|
+
/* Negative */
|
75
|
+
body .negative {
|
76
|
+
color:#d12f19;
|
77
|
+
}
|
78
|
+
button.negative:hover {
|
79
|
+
background:#fbe3e4;
|
80
|
+
border:1px solid #fbc2c4;
|
81
|
+
color:#d12f19;
|
82
|
+
}
|