gitdocs 0.4.3 → 0.4.5
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/CHANGELOG +15 -1
- data/README.md +5 -5
- data/gitdocs.gemspec +2 -0
- data/lib/gitdocs.rb +8 -2
- data/lib/gitdocs/cli.rb +2 -2
- data/lib/gitdocs/docfile.rb +9 -1
- data/lib/gitdocs/manager.rb +45 -29
- data/lib/gitdocs/public/css/app.css +3 -3
- data/lib/gitdocs/public/img/file.png +0 -0
- data/lib/gitdocs/public/img/folder.png +0 -0
- data/lib/gitdocs/public/js/app.js +13 -2
- data/lib/gitdocs/public/js/jquery.tablesorter.js +4 -0
- data/lib/gitdocs/public/js/util.js +25 -0
- data/lib/gitdocs/rendering.rb +8 -0
- data/lib/gitdocs/runner.rb +3 -1
- data/lib/gitdocs/server.rb +6 -3
- data/lib/gitdocs/version.rb +1 -1
- data/lib/gitdocs/views/app.haml +1 -0
- data/lib/gitdocs/views/dir.haml +4 -1
- data/test/test_helper.rb +1 -1
- metadata +36 -10
data/CHANGELOG
CHANGED
@@ -11,4 +11,18 @@
|
|
11
11
|
|
12
12
|
* Javascript fixes for front-end
|
13
13
|
|
14
|
-
0.4.4 (
|
14
|
+
0.4.4 (12/14/2012)
|
15
|
+
|
16
|
+
* Lock to eventmachine 1.0
|
17
|
+
* Use mime-types over file for better platform support
|
18
|
+
* Remove signal handling and just leverage EM start/stop
|
19
|
+
* Adds table sorting and file+folder icons in web front-end
|
20
|
+
|
21
|
+
0.4.5 (12/14/2012)
|
22
|
+
|
23
|
+
* Enables logs in ~/.gitdocs/log for easier debugging
|
24
|
+
* Fix issue with default sort order on web interface
|
25
|
+
* Fixes major mime type detection issues
|
26
|
+
* Fixes rendering issues
|
27
|
+
|
28
|
+
0.4.6 (Not yet released)
|
data/README.md
CHANGED
@@ -67,7 +67,7 @@ You need to start gitdocs in order for the monitoring to work:
|
|
67
67
|
gitdocs start
|
68
68
|
```
|
69
69
|
|
70
|
-
If the start command fails, you can run again with
|
70
|
+
If the start command fails, you can check the logs in `~/.gitdocs/log` or run again with the debug flag:
|
71
71
|
|
72
72
|
```
|
73
73
|
gitdocs start -D
|
@@ -110,7 +110,7 @@ gitdocs clear
|
|
110
110
|
|
111
111
|
### Web Front-end
|
112
112
|
|
113
|
-
Gitdocs come with a handy web front-end that is available.
|
113
|
+
Gitdocs come with a handy web front-end that is available.
|
114
114
|
|
115
115
|
<a href="http://i.imgur.com/IMwqN.png">
|
116
116
|
<img src="http://i.imgur.com/IMwqN.png" width="250" />
|
@@ -140,8 +140,8 @@ Proper conflict resolution is an important part of any good doc and file collabo
|
|
140
140
|
In most cases, git does a good job of handling file merges for you. Still, what about cases where the conflict cannot be
|
141
141
|
resolved automatically?
|
142
142
|
|
143
|
-
Don't worry, gitdocs makes handling this simple. In the event of a conflict,
|
144
|
-
**all the different versions of a document are stored** in the repo tagged with the **git sha** for each
|
143
|
+
Don't worry, gitdocs makes handling this simple. In the event of a conflict,
|
144
|
+
**all the different versions of a document are stored** in the repo tagged with the **git sha** for each
|
145
145
|
committed version. The members of the repo can then compare all versions and resolve the conflict.
|
146
146
|
|
147
147
|
## Planned Features
|
@@ -158,7 +158,7 @@ Gitdocs is a young project but we have big plans for it including:
|
|
158
158
|
Gitdocs is a fresh project that we spiked on in a few days time. Our primary goals are to keep the code as simple as possible,
|
159
159
|
but provide the features that makes dropbox great. If you are interested in other Dropbox alternatives, be sure to checkout our notes below:
|
160
160
|
|
161
|
-
* [SparkleShare](http://sparkleshare.org/) is an open source, self-hosted Dropbox alternative written using C# and the [Mono Project](http://www.mono-project.com/Main_Page).
|
161
|
+
* [SparkleShare](http://sparkleshare.org/) is an open source, self-hosted Dropbox alternative written using C# and the [Mono Project](http://www.mono-project.com/Main_Page).
|
162
162
|
More mature but has a lot of dependencies, and lacks some of the features planned in Gitdocs.
|
163
163
|
* [DVCS-Autosync](http://mayrhofer.eu.org/dvcs-autosync) is a project to create an open source replacement for Dropbox based on distributed version control systems.
|
164
164
|
Very similar project but again we have features planned that are out of scope (local tunnel file sharing, complete web ui for browsing, uploading and editing).
|
data/gitdocs.gemspec
CHANGED
@@ -32,6 +32,8 @@ Gem::Specification.new do |s|
|
|
32
32
|
s.add_dependency 'activerecord', "~> 3.1.0"
|
33
33
|
s.add_dependency 'grit', "~> 2.4.1"
|
34
34
|
s.add_dependency 'shell_tools', "~> 0.1.0"
|
35
|
+
s.add_dependency 'mimetype-fu', "~> 0.1.2"
|
36
|
+
s.add_dependency 'eventmachine', '>= 1.0.0.beta.3'
|
35
37
|
|
36
38
|
s.add_development_dependency 'minitest', "~> 2.6.1"
|
37
39
|
s.add_development_dependency 'rake'
|
data/lib/gitdocs.rb
CHANGED
@@ -12,17 +12,23 @@ require 'gitdocs/server'
|
|
12
12
|
require 'gitdocs/cli'
|
13
13
|
require 'gitdocs/manager'
|
14
14
|
require 'gitdocs/docfile'
|
15
|
+
require 'gitdocs/rendering'
|
15
16
|
|
16
17
|
module Gitdocs
|
17
18
|
|
18
19
|
DEBUG = ENV['DEBUG']
|
19
20
|
|
20
|
-
def self.
|
21
|
+
def self.start(config_root = nil, debug = DEBUG, &blk)
|
22
|
+
@manager.stop if @manager
|
21
23
|
@manager = Manager.new(config_root, debug, &blk)
|
22
|
-
@manager.
|
24
|
+
@manager.start
|
23
25
|
end
|
24
26
|
|
25
27
|
def self.restart
|
26
28
|
@manager.restart
|
27
29
|
end
|
30
|
+
|
31
|
+
def self.stop
|
32
|
+
@manager.stop
|
33
|
+
end
|
28
34
|
end
|
data/lib/gitdocs/cli.rb
CHANGED
@@ -10,11 +10,11 @@ module Gitdocs
|
|
10
10
|
method_option :debug, :type => :boolean, :aliases => "-D"
|
11
11
|
def start
|
12
12
|
if self.stopped? && !options[:debug]
|
13
|
-
self.runner.execute { Gitdocs.
|
13
|
+
self.runner.execute { Gitdocs.start }
|
14
14
|
self.running? ? say("Started gitdocs", :green) : say("Failed to start gitdocs", :red)
|
15
15
|
elsif self.stopped? && options[:debug]
|
16
16
|
say "Starting in debug mode", :yellow
|
17
|
-
Gitdocs.
|
17
|
+
Gitdocs.start(nil, true)
|
18
18
|
else # already running
|
19
19
|
say "Gitdocs is already running, please use restart", :red
|
20
20
|
end
|
data/lib/gitdocs/docfile.rb
CHANGED
@@ -14,6 +14,10 @@ module Gitdocs
|
|
14
14
|
File.expand_path(@parent, root) == expanded_root ||
|
15
15
|
File.expand_path(@path, root).include?(expanded_root)
|
16
16
|
end
|
17
|
+
|
18
|
+
def file?
|
19
|
+
true
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
23
|
class Docdir < Docfile
|
@@ -27,11 +31,15 @@ module Gitdocs
|
|
27
31
|
end
|
28
32
|
|
29
33
|
def items
|
30
|
-
subdirs + files
|
34
|
+
(subdirs + files).sort { |a,b| a.name.downcase <=> b.name.downcase }
|
31
35
|
end
|
32
36
|
|
33
37
|
def parent=(dir)
|
34
38
|
dir.subdirs.push(self) if dir
|
35
39
|
end
|
40
|
+
|
41
|
+
def file?
|
42
|
+
false
|
43
|
+
end
|
36
44
|
end
|
37
45
|
end
|
data/lib/gitdocs/manager.rb
CHANGED
@@ -6,6 +6,7 @@ module Gitdocs
|
|
6
6
|
|
7
7
|
def initialize(config_root, debug)
|
8
8
|
@config = Configuration.new(config_root)
|
9
|
+
@logger = Logger.new(File.expand_path('log', @config.config_root))
|
9
10
|
@debug = debug
|
10
11
|
yield @config if block_given?
|
11
12
|
end
|
@@ -22,41 +23,56 @@ module Gitdocs
|
|
22
23
|
results
|
23
24
|
end
|
24
25
|
|
25
|
-
def
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
runners
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
web_started =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
i += 1
|
49
|
-
retry if i <= 20
|
50
|
-
end
|
51
|
-
system("open http://localhost:8888/") if self.config.global.load_browser_on_startup && web_started
|
26
|
+
def start
|
27
|
+
self.log "Starting Gitdocs v#{VERSION}..."
|
28
|
+
self.log "Using configuration root: '#{self.config.config_root}'"
|
29
|
+
self.log "Shares: #{config.shares.map(&:inspect).join(", ")}"
|
30
|
+
# Start the repo watchers
|
31
|
+
runners = nil
|
32
|
+
EM.run do
|
33
|
+
self.log "Starting EM loop..."
|
34
|
+
@runners = config.shares.map { |share| Runner.new(share) }
|
35
|
+
@runners.each(&:run)
|
36
|
+
# Start the web front-end
|
37
|
+
if self.config.global.start_web_frontend
|
38
|
+
Server.new(self, *@runners).start
|
39
|
+
i = 0
|
40
|
+
web_started = false
|
41
|
+
begin
|
42
|
+
TCPSocket.open('127.0.0.1', 8888).close
|
43
|
+
web_started = true
|
44
|
+
rescue Errno::ECONNREFUSED
|
45
|
+
self.log "Retrying server loop..."
|
46
|
+
sleep 0.2
|
47
|
+
i += 1
|
48
|
+
retry if i <= 20
|
52
49
|
end
|
50
|
+
self.log "Web server running: #{web_started}"
|
51
|
+
system("open http://localhost:8888/") if self.config.global.load_browser_on_startup && web_started
|
53
52
|
end
|
54
|
-
sleep(10) if @runners && @runners.empty?
|
55
53
|
end
|
54
|
+
rescue Exception => e # Report all errors in log
|
55
|
+
self.log(e.class.inspect + " - " + e.inspect + " - " + e.message.inspect, :error)
|
56
|
+
self.log(e.backtrace.join("\n"), :error)
|
57
|
+
ensure
|
58
|
+
self.log("Gitdocs is terminating...goodbye\n\n")
|
56
59
|
end
|
57
60
|
|
58
61
|
def restart
|
59
|
-
|
62
|
+
stop
|
63
|
+
start
|
64
|
+
end
|
65
|
+
|
66
|
+
def stop
|
67
|
+
EM.stop
|
68
|
+
end
|
69
|
+
|
70
|
+
protected
|
71
|
+
|
72
|
+
# Logs and outputs to file or stdout based on debugging state
|
73
|
+
# log("message")
|
74
|
+
def log(msg, level=:info)
|
75
|
+
@debug ? puts(msg) : @logger.send(level, msg)
|
60
76
|
end
|
61
77
|
end
|
62
78
|
end
|
@@ -28,9 +28,9 @@ form.upload p, form.add p {
|
|
28
28
|
}
|
29
29
|
|
30
30
|
/* Dir Listing */
|
31
|
-
table td
|
32
|
-
|
33
|
-
}
|
31
|
+
table td img { vertical-align: middle; }
|
32
|
+
table td.author, td.modified { width: 30%; }
|
33
|
+
table td.size { width: 15%; }
|
34
34
|
|
35
35
|
/* Settings */
|
36
36
|
div.share {
|
Binary file
|
Binary file
|
@@ -15,13 +15,24 @@ GitDocs = {
|
|
15
15
|
},
|
16
16
|
// fills in directory meta author and modified for every file
|
17
17
|
fillDirMeta : function(){
|
18
|
-
$('table
|
18
|
+
$('table#fileListing tbody tr').each(function(i, e) {
|
19
19
|
var file = $(e).find('a').attr('href');
|
20
|
+
var fileListingBody = $('table#fileListing tbody')
|
20
21
|
$.getJSON(file + "?mode=meta", function(data) {
|
21
|
-
$(e).find('td.author').html(data.author);
|
22
|
+
$(e).addClass('loaded').find('td.author').html(data.author);
|
22
23
|
$(e).find('td.modified').html(RelativeDate.time_ago_in_words(data.modified));
|
24
|
+
$(e).find('td.size').html(Utils.humanizeBytes(data.size)).data("val", data.size);
|
25
|
+
if ($(fileListingBody).find('tr').length == $(fileListingBody).find('tr.loaded').length) {
|
26
|
+
GitDocs.pageLoaded(); // Fire on completion
|
27
|
+
}
|
23
28
|
});
|
24
29
|
});
|
30
|
+
},
|
31
|
+
// Fire when the page is finished loading
|
32
|
+
pageLoaded : function() {
|
33
|
+
// Enable table sorter
|
34
|
+
var extractor = function(e) { return $(e).data('val') || $(e).text() }
|
35
|
+
$("table#fileListing").tablesorter({ textExtraction : extractor, sortList: [[0,0]] });
|
25
36
|
}
|
26
37
|
};
|
27
38
|
|
@@ -0,0 +1,4 @@
|
|
1
|
+
|
2
|
+
(function($){$.extend({tablesorter:new
|
3
|
+
function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1
|
4
|
+
var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
|
@@ -13,6 +13,31 @@ Utils = {
|
|
13
13
|
values.push(hash[i]);
|
14
14
|
}
|
15
15
|
return values;
|
16
|
+
},
|
17
|
+
// humanizeBytes(1234)
|
18
|
+
humanizeBytes : function(filesize) {
|
19
|
+
if (filesize == null || filesize <= 0 || filesize == "") { return "—" }
|
20
|
+
if (filesize >= 1073741824) {
|
21
|
+
filesize = Utils.number_format(filesize / 1073741824, 2, '.', '') + ' Gb';
|
22
|
+
} else {
|
23
|
+
if (filesize >= 1048576) {
|
24
|
+
filesize = Utils.number_format(filesize / 1048576, 2, '.', '') + ' Mb';
|
25
|
+
} else {
|
26
|
+
if (filesize >= 1024) {
|
27
|
+
filesize = Utils.number_format(filesize / 1024, 0) + ' Kb';
|
28
|
+
} else {
|
29
|
+
filesize = Utils.number_format(filesize, 0) + ' bytes';
|
30
|
+
};
|
31
|
+
};
|
32
|
+
};
|
33
|
+
return filesize;
|
34
|
+
},
|
35
|
+
number_format : function( number, decimals, dec_point, thousands_sep ) {
|
36
|
+
var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
|
37
|
+
var d = dec_point == undefined ? "," : dec_point;
|
38
|
+
var t = thousands_sep == undefined ? "." : thousands_sep, s = n < 0 ? "-" : "";
|
39
|
+
var i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "", j = (j = i.length) > 3 ? j % 3 : 0;
|
40
|
+
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
|
16
41
|
}
|
17
42
|
};
|
18
43
|
|
data/lib/gitdocs/runner.rb
CHANGED
@@ -155,9 +155,11 @@ module Gitdocs
|
|
155
155
|
|
156
156
|
def file_meta(file)
|
157
157
|
file = file.gsub(%r{^/}, '')
|
158
|
+
full_path = File.expand_path(file, @root)
|
158
159
|
author, modified = sh_string("git log --format='%aN|%ai' -n1 #{ShellTools.escape(file)}").split("|")
|
159
160
|
modified = Time.parse(modified.sub(' ', 'T')).utc.iso8601
|
160
|
-
|
161
|
+
size = (File.symlink?(full_path) || File.directory?(full_path)) ? -1 : File.size(full_path)
|
162
|
+
{ :author => author, :size => size, :modified => modified }
|
161
163
|
end
|
162
164
|
|
163
165
|
def valid?
|
data/lib/gitdocs/server.rb
CHANGED
@@ -3,6 +3,7 @@ require 'renee'
|
|
3
3
|
require 'coderay'
|
4
4
|
require 'uri'
|
5
5
|
require 'haml'
|
6
|
+
require 'mimetype_fu'
|
6
7
|
|
7
8
|
module Gitdocs
|
8
9
|
class Server
|
@@ -14,6 +15,7 @@ module Gitdocs
|
|
14
15
|
def start(port = 8888)
|
15
16
|
gds = @gitdocs
|
16
17
|
manager = @manager
|
18
|
+
Thin::Logging.debug = @manager.debug
|
17
19
|
Thin::Server.start('127.0.0.1', port) do
|
18
20
|
use Rack::Static, :urls => ['/css', '/js', '/img', '/doc'], :root => File.expand_path("../public", __FILE__)
|
19
21
|
run Renee {
|
@@ -51,9 +53,10 @@ module Gitdocs
|
|
51
53
|
parent = '' if parent == '/'
|
52
54
|
parent = nil if parent == '.'
|
53
55
|
locals = {:idx => idx, :parent => parent, :root => gd.root, :file_path => expanded_path, :nav_state => nil }
|
54
|
-
|
56
|
+
mime = File.mime_type?(File.open(expanded_path)) if File.file?(expanded_path)
|
57
|
+
mode = request.params['mode']
|
55
58
|
if mode == 'meta' # Meta
|
56
|
-
halt 200, { 'Content-Type' => 'application/json' }, gd.file_meta(file_path).to_json
|
59
|
+
halt 200, { 'Content-Type' => 'application/json' }, [gd.file_meta(file_path).to_json]
|
57
60
|
elsif mode == 'save' # Saving
|
58
61
|
File.open(expanded_path, 'w') { |f| f.print request.params['data'] }
|
59
62
|
redirect! "/" + idx.to_s + file_path
|
@@ -75,7 +78,7 @@ module Gitdocs
|
|
75
78
|
render! "edit", :layout => 'app', :locals => locals.merge(:contents => contents)
|
76
79
|
elsif mode != 'raw' # render file
|
77
80
|
begin # attempting to render file
|
78
|
-
contents = '<div class="tilt">'
|
81
|
+
contents = '<div class="tilt">' + render(expanded_path) + '</div>'
|
79
82
|
rescue RuntimeError => e # not tilt supported
|
80
83
|
contents = if mime.match(%r{text/})
|
81
84
|
'<pre class="CodeRay">' + CodeRay.scan_file(expanded_path).encode(:html) + '</pre>'
|
data/lib/gitdocs/version.rb
CHANGED
data/lib/gitdocs/views/app.haml
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
%link{ :href => "/css/coderay.css", :rel => "stylesheet" }
|
9
9
|
%script{ :src => "/js/util.js", :type => "text/javascript", :charset => "utf-8" }
|
10
10
|
%script{ :src => "/js/jquery.js", :type => "text/javascript", :charset => "utf-8" }
|
11
|
+
%script{ :src => "/js/jquery.tablesorter.js", :type => "text/javascript", :charset => "utf-8" }
|
11
12
|
%script{ :src => "/js/app.js", :type => "text/javascript", :charset => "utf-8" }
|
12
13
|
%body
|
13
14
|
#nav.topbar
|
data/lib/gitdocs/views/dir.haml
CHANGED
@@ -2,21 +2,24 @@
|
|
2
2
|
|
3
3
|
= partial("header", :locals => { :parent => parent, :file => false, :idx => idx })
|
4
4
|
|
5
|
-
%table.condensed-table.zebra-striped
|
5
|
+
%table#fileListing.condensed-table.zebra-striped
|
6
6
|
%thead
|
7
7
|
%tr
|
8
8
|
%th File
|
9
9
|
%th Author
|
10
10
|
%th Last Modified
|
11
|
+
%th Size
|
11
12
|
|
12
13
|
%tbody
|
13
14
|
- contents.items.each_with_index do |f, i|
|
14
15
|
%tr
|
15
16
|
%td
|
17
|
+
%img{ :src => "/img/#{f.file? ? 'file' : 'folder'}.png", :width => 16, :height => 16 }
|
16
18
|
%a{ :href => "/#{idx}#{request.path_info}/#{f.name}" }
|
17
19
|
= f.name
|
18
20
|
%td.author
|
19
21
|
%td.modified
|
22
|
+
%td.size
|
20
23
|
|
21
24
|
.row
|
22
25
|
.span6
|
data/test/test_helper.rb
CHANGED
@@ -31,7 +31,7 @@ class MiniTest::Spec
|
|
31
31
|
end
|
32
32
|
begin
|
33
33
|
puts "RUNNING!"
|
34
|
-
Gitdocs.
|
34
|
+
Gitdocs.start(conf_path) do |conf|
|
35
35
|
conf.global.update_attributes(:load_browser_on_startup => false, :start_web_frontend => false)
|
36
36
|
conf.add_path(path, :polling_interval => 0.1, :notification => false)
|
37
37
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: gitdocs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.4.
|
5
|
+
version: 0.4.5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Josh Hull
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2011-12-
|
14
|
+
date: 2011-12-15 00:00:00 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: joshbuddy-guard
|
@@ -168,49 +168,71 @@ dependencies:
|
|
168
168
|
type: :runtime
|
169
169
|
version_requirements: *id014
|
170
170
|
- !ruby/object:Gem::Dependency
|
171
|
-
name:
|
171
|
+
name: mimetype-fu
|
172
172
|
prerelease: false
|
173
173
|
requirement: &id015 !ruby/object:Gem::Requirement
|
174
|
+
none: false
|
175
|
+
requirements:
|
176
|
+
- - ~>
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: 0.1.2
|
179
|
+
type: :runtime
|
180
|
+
version_requirements: *id015
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: eventmachine
|
183
|
+
prerelease: false
|
184
|
+
requirement: &id016 !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: 1.0.0.beta.3
|
190
|
+
type: :runtime
|
191
|
+
version_requirements: *id016
|
192
|
+
- !ruby/object:Gem::Dependency
|
193
|
+
name: minitest
|
194
|
+
prerelease: false
|
195
|
+
requirement: &id017 !ruby/object:Gem::Requirement
|
174
196
|
none: false
|
175
197
|
requirements:
|
176
198
|
- - ~>
|
177
199
|
- !ruby/object:Gem::Version
|
178
200
|
version: 2.6.1
|
179
201
|
type: :development
|
180
|
-
version_requirements: *
|
202
|
+
version_requirements: *id017
|
181
203
|
- !ruby/object:Gem::Dependency
|
182
204
|
name: rake
|
183
205
|
prerelease: false
|
184
|
-
requirement: &
|
206
|
+
requirement: &id018 !ruby/object:Gem::Requirement
|
185
207
|
none: false
|
186
208
|
requirements:
|
187
209
|
- - ">="
|
188
210
|
- !ruby/object:Gem::Version
|
189
211
|
version: "0"
|
190
212
|
type: :development
|
191
|
-
version_requirements: *
|
213
|
+
version_requirements: *id018
|
192
214
|
- !ruby/object:Gem::Dependency
|
193
215
|
name: mocha
|
194
216
|
prerelease: false
|
195
|
-
requirement: &
|
217
|
+
requirement: &id019 !ruby/object:Gem::Requirement
|
196
218
|
none: false
|
197
219
|
requirements:
|
198
220
|
- - ">="
|
199
221
|
- !ruby/object:Gem::Version
|
200
222
|
version: "0"
|
201
223
|
type: :development
|
202
|
-
version_requirements: *
|
224
|
+
version_requirements: *id019
|
203
225
|
- !ruby/object:Gem::Dependency
|
204
226
|
name: fakeweb
|
205
227
|
prerelease: false
|
206
|
-
requirement: &
|
228
|
+
requirement: &id020 !ruby/object:Gem::Requirement
|
207
229
|
none: false
|
208
230
|
requirements:
|
209
231
|
- - ">="
|
210
232
|
- !ruby/object:Gem::Version
|
211
233
|
version: "0"
|
212
234
|
type: :development
|
213
|
-
version_requirements: *
|
235
|
+
version_requirements: *id020
|
214
236
|
description: Open-source Dropbox using Ruby and Git.
|
215
237
|
email:
|
216
238
|
- joshbuddy@gmail.com
|
@@ -245,6 +267,8 @@ files:
|
|
245
267
|
- lib/gitdocs/public/css/coderay.css
|
246
268
|
- lib/gitdocs/public/css/tilt.css
|
247
269
|
- lib/gitdocs/public/img/error.png
|
270
|
+
- lib/gitdocs/public/img/file.png
|
271
|
+
- lib/gitdocs/public/img/folder.png
|
248
272
|
- lib/gitdocs/public/img/git_logo.png
|
249
273
|
- lib/gitdocs/public/img/info.png
|
250
274
|
- lib/gitdocs/public/img/ok.png
|
@@ -281,8 +305,10 @@ files:
|
|
281
305
|
- lib/gitdocs/public/js/app.js
|
282
306
|
- lib/gitdocs/public/js/edit.js
|
283
307
|
- lib/gitdocs/public/js/jquery.js
|
308
|
+
- lib/gitdocs/public/js/jquery.tablesorter.js
|
284
309
|
- lib/gitdocs/public/js/search.js
|
285
310
|
- lib/gitdocs/public/js/util.js
|
311
|
+
- lib/gitdocs/rendering.rb
|
286
312
|
- lib/gitdocs/runner.rb
|
287
313
|
- lib/gitdocs/server.rb
|
288
314
|
- lib/gitdocs/version.rb
|