gitdocs 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,12 +1,47 @@
1
1
  # Gitdocs
2
2
 
3
- Collaborate on files and docs through a shared git repository. gitdocs will automatically push changes to the repo as well as pull in changes.
4
- This allows any git repo to be used as a collaborative task list or wiki for a team.
5
- You can also start a web front-end allowing the repo to be accessed through a browser.
3
+ Open-source dropbox alternative powered by git. Collaborate on files and tasks without any extra hassle.
4
+ gitdocs will automatically keep everyone's repos in sync by pushing and pulling changes.
5
+ This allows any git repo to be used as a collaborative task list, file share, or wiki for a team.
6
+ Supports a web front-end allowing each repo to be accessed through your browser.
7
+
8
+ **Note:** Right now, gitdocs only supports Mac OSX using fsevent. Linux and windows support are coming very soon, so check back here again.
9
+
10
+ ## Why?
11
+
12
+ Why should you use gitdocs for your file and doc sharing needs?
13
+
14
+ * **Open** - gitdocs is entirely open-source under the MIT license
15
+ * **Simple** - gitdocs is the simplest thing that works in both setup and usage
16
+ * **Secure** - gitdocs leverages git (and existing providers like github) to store your data safely.
17
+ * **Versatile** - share task lists, code snippets, images, files or just use it as a wiki (with our web front-end)
18
+ * **Portable** - access your files anywhere you can use git (with upcoming cross-platform support)
19
+
20
+ The best part is that giving this a try is quick and easy.
21
+
22
+ ## Quick Start
23
+
24
+ Gitdocs monitors any number of directories for changes and keeps them automatically synced. You can either add
25
+ existing git directories to be watched or have gitdocs pull down a repository for you.
26
+
27
+ There are plenty of great git hosting providers to safely store your data and you can trust the data is stored securely.
28
+ If you want a private repo to use with gitdocs, we recommend you check out [BitBucket](https://bitbucket.org/) which
29
+ provides free private git repos after registration.
30
+
31
+ To get started with gitdocs and a secure private bitbucket repo:
32
+
33
+ - `gem install gitdocs`
34
+ - `gitdocs start`
35
+ - Login to [BitBucket](https://bitbucket.org/) and add a new private repo named 'docs'
36
+ - Setup your SSH Key under [Account](https://bitbucket.org/account/) for ssh access
37
+ - `gitdocs create ~/Documents/gitdocs git@bitbucket.org:username/docs.git`
38
+
39
+ There you go! Now just start adding and editing files within the directory and they will be automatically
40
+ synchronized across all gitdocs-enabled clients.
6
41
 
7
42
  ## Installation
8
43
 
9
- Install the gem:
44
+ Requires ruby and rubygems. Install as a gem:
10
45
 
11
46
  ```
12
47
  gem install gitdocs
@@ -22,8 +57,7 @@ to enable Growl support (other platforms coming soon).
22
57
 
23
58
  ## Usage
24
59
 
25
- Gitdocs is centered around 'watching' any number of directories for changes and keeping them automatically synced. You can either add
26
- existing git directories for monitoring or have gitdocs pull down a repository to monitor.
60
+ ### Monitoring Repos
27
61
 
28
62
  You can add existing folders to watch:
29
63
 
@@ -44,6 +78,8 @@ gitdocs rm my/path/to/watch
44
78
  gitdocs clear
45
79
  ```
46
80
 
81
+ ### Starting Gitdocs
82
+
47
83
  You need to start gitdocs in order for the monitoring to work:
48
84
 
49
85
  ```
@@ -56,29 +92,33 @@ If the start command fails, you can run again with a debug flag:
56
92
  gitdocs start -D
57
93
  ```
58
94
 
59
- and gitdocs can be easily stopped and restarted:
95
+ Once gitdocs has been started and is monitoring the correct directories, simply start editing or adding files to your
96
+ designated git repos and changes will be automatically pushed. Gitdocs can be easily stopped or restarted:
60
97
 
61
98
  ```
62
99
  gitdocs stop
63
100
  gitdocs restart
64
101
  ```
65
102
 
103
+ ### Exploring Gitdocs
104
+
66
105
  For an overview of gitdocs current status, run:
67
106
 
68
107
  ```
69
108
  gitdocs status
70
109
  ```
71
110
 
72
- Once gitdocs has been started and is monitoring the correct directories, simply start editing or adding files to your
73
- designated git repos. Changes will be automatically pushed and pulled to your local repos.
111
+ To explore the repos in your browser, simply visit `http://localhost:8888` for access to all your docs within the browser.
74
112
 
75
- To explore the repos in your browser, simply start the server:
113
+ ### Conflict Resolution
76
114
 
77
- ```
78
- gitdocs serve
79
- ```
115
+ Proper conflict resolution is an important part of any good doc and file collaboration tool.
116
+ In most cases, git does a good job of handling file merges for you. Still, what about cases where the conflict cannot be
117
+ resolved automatically?
80
118
 
81
- and then visit `http://localhost:8888` for access to all your docs in the browser.
119
+ Don't worrry, gitdocs makes this easy. In the event of a conflict, **all the different versions
120
+ of a document are stored** in the repo tagged with the **git sha** for the commit for each variation. The members
121
+ of the repo can then compare all versions and resolve the conflict.
82
122
 
83
123
  ## Planned Features
84
124
 
@@ -87,7 +127,6 @@ Gitdocs is a young project but we have big plans for it including:
87
127
  - A web front-end UI for file uploading and editing of files (with rich text editor and syntax highlighting)
88
128
  - Local-area peer-to-peer syncing, avoid 'polling' in cases where we can using a messaging protocol.
89
129
  - Click-to-share instant access granting file access to users using a local tunnel or other means.
90
- - Better conflict-resolution behavior on updates (maintain both versions of a file)
91
130
  - Support for linux and windows platforms (coming soon), and maybe android and iOS as well?
92
131
 
93
132
  ## Prior Projects
@@ -96,9 +135,11 @@ Gitdocs is a fresh project that we spiked on in a few days time. Our primary goa
96
135
  but provide the features that makes dropbox great. If you are interested in other Dropbox alternatives, be sure to checkout our notes below:
97
136
 
98
137
  * [SparkleShare](http://sparkleshare.org/) is an open source, self-hosted Dropbox alternative. Nice project and a great alternative but has a lot of dependencies,
99
- more complex codebase, and lacks some of the features we have planned for gitdocs in the near future.
138
+ and lacks some of the features we have planned for gitdocs in the near future. More mature project, so be sure to take a look.
100
139
  * [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.
101
140
  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).
102
141
  * [Lipsync](https://github.com/philcryer/lipsync) is another similar project. We haven't looked at this too closely, but thought we would mention it in this list.
142
+ * [bitpocket](https://github.com/sickill/bitpocket) is a project that uses rsync to synchronize data. Interesting concept, but
143
+ lacks revision history, author tracking, etc and we have features planned that are out of scope for this project
103
144
 
104
145
  If any other open-source dropbox alternatives are available, we would love to hear about them so let us know!
data/gitdocs.gemspec CHANGED
@@ -26,6 +26,7 @@ Gem::Specification.new do |s|
26
26
  s.add_dependency 'dante', '~> 0.0.4'
27
27
  s.add_dependency 'growl', '~> 1.0.3'
28
28
  s.add_dependency 'yajl-ruby'
29
+ s.add_dependency 'haml'
29
30
 
30
31
  s.add_development_dependency 'minitest', "~> 2.6.1"
31
32
  s.add_development_dependency 'rake'
data/lib/gitdocs.rb CHANGED
@@ -9,21 +9,37 @@ require 'growl'
9
9
  require 'yajl'
10
10
  require 'dante'
11
11
 
12
+
12
13
  module Gitdocs
13
- def self.run(config_root = nil, debug=false)
14
+
15
+ DEBUG = ENV['DEBUG']
16
+
17
+ def self.run(config_root = nil, debug = DEBUG)
14
18
  loop do
15
- @config = Configuration.new(config_root)
19
+ config = Configuration.new(config_root)
16
20
  puts "Gitdocs v#{VERSION}" if debug
17
- puts "Using configuration root: '#{@config.config_root}'" if debug
18
- puts "Watch paths: #{@config.paths.join(", ")}" if debug
19
- @threads = @config.paths.map do |path|
20
- t = Thread.new { Runner.new(path).run }
21
+ puts "Using configuration root: '#{config.config_root}'" if debug
22
+ puts "Watch paths: #{config.paths.join(", ")}" if debug
23
+ # Start the repo watchers
24
+ runners = []
25
+ threads = config.paths.map do |path|
26
+ t = Thread.new(runners) { |r|
27
+ runner = Runner.new(path)
28
+ r << runner
29
+ runner.run
30
+ }
21
31
  t.abort_on_exception = true
22
32
  t
23
33
  end
24
- puts "Watch threads: #{@threads.map { |t| "Thread status: '#{t.status}', running: #{t.alive?}" }}" if debug
25
- puts "Joined #{@threads.size} watch threads...running" if debug
26
- @threads.each(&:join)
34
+ sleep 1
35
+ unless defined?(pid) && pid
36
+ # Start the web front-end
37
+ pid = fork { Server.new(*runners).start }
38
+ at_exit { Process.kill("KILL", pid) rescue nil }
39
+ end
40
+ puts "Watch threads: #{threads.map { |t| "Thread status: '#{t.status}', running: #{t.alive?}" }}" if debug
41
+ puts "Joined #{threads.size} watch threads...running" if debug
42
+ threads.each(&:join)
27
43
  sleep(60)
28
44
  end
29
45
  end
data/lib/gitdocs/cli.rb CHANGED
@@ -75,12 +75,6 @@ module Gitdocs
75
75
  say self.config.paths.map { |p| " - #{p}" }.join("\n")
76
76
  end
77
77
 
78
- desc "serve", "Serves web frontend for files"
79
- def serve
80
- puts "Serving docs..."
81
- Gitdocs::Server.new(*self.config.paths.map{|p| Gitdocs::Runner.new(p)}).start
82
- end
83
-
84
78
  desc "config", "Configuration options for gitdocs"
85
79
  def config
86
80
  # TODO make this work
@@ -0,0 +1,46 @@
1
+ body {
2
+ margin-left: 20%;
3
+ margin-right: 20%;
4
+ font-family: Arial, Verdana;
5
+ }
6
+
7
+ body h1, h2 {
8
+ margin: 0;
9
+ padding-bottom: 0.8em;
10
+ font-weight: bold;
11
+ }
12
+ body h1 { font-size: 2em; }
13
+ body h2 { font-size: 1.5em; margin-top: 0.2em; }
14
+
15
+ body .container {
16
+ min-width: 500px;
17
+ background: #FCEA97;
18
+ border-style: solid;
19
+ border-width: 5px;
20
+ border-color: #FFC003;
21
+ border-radius: 15px;
22
+ padding: 2em;
23
+ margin-top: 1.2em;
24
+ }
25
+
26
+ body a { text-decoration: none; color: blue; }
27
+ body a:hover { text-decoration: underline; }
28
+
29
+ body .contents {
30
+ overflow: auto;
31
+ background-color: #F8F8F8;
32
+ border: 3px solid #EFEFEF;
33
+ padding: 1.2em;
34
+ margin: 0;
35
+ font-family: ;
36
+ }
37
+
38
+ body .contents h1 {
39
+ font-size: 2em;
40
+ padding-bottom: 0.8em;
41
+ }
42
+
43
+ body .contents h2 {
44
+ font-size: 1.4em;
45
+ padding-bottom: 0.6em;
46
+ }
@@ -0,0 +1,59 @@
1
+ /*
2
+ Copyright (c) 2010, Yahoo! Inc. All rights reserved.
3
+ Code licensed under the BSD License:
4
+ http://developer.yahoo.com/yui/license.html
5
+ version: 3.1.1
6
+ build: 47
7
+ */
8
+ html {
9
+ color: #000;
10
+ background: #FFF; }
11
+
12
+ body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, code, form, fieldset, legend, input, textarea, p, blockquote, th, td {
13
+ margin: 0;
14
+ padding: 0; }
15
+
16
+ table {
17
+ border-collapse: collapse;
18
+ border-spacing: 0; }
19
+
20
+ fieldset, img {
21
+ border: 0; }
22
+
23
+ address, caption, cite, code, dfn, em, strong, th, var {
24
+ font-style: normal;
25
+ font-weight: normal; }
26
+
27
+ li {
28
+ list-style: none; }
29
+
30
+ caption, th {
31
+ text-align: left; }
32
+
33
+ h1, h2, h3, h4, h5, h6 {
34
+ font-size: 100%;
35
+ font-weight: normal; }
36
+
37
+ q:before, q:after {
38
+ content: ''; }
39
+
40
+ abbr, acronym {
41
+ border: 0;
42
+ font-variant: normal; }
43
+
44
+ sup {
45
+ vertical-align: text-top; }
46
+
47
+ sub {
48
+ vertical-align: text-bottom; }
49
+
50
+ input, textarea, select {
51
+ font-family: inherit;
52
+ font-size: inherit;
53
+ font-weight: inherit; }
54
+
55
+ input, textarea, select {
56
+ *font-size: 100%; }
57
+
58
+ legend {
59
+ color: #000; }
@@ -7,70 +7,88 @@ module Gitdocs
7
7
  out, status = sh_with_code "which growlnotify"
8
8
  @use_growl = opts && opts.key?(:growl) ? opts[:growl] : status.success?
9
9
  @polling_interval = opts && opts[:polling_interval] || 15
10
- @icon = File.expand_path("../img/icon.png", __FILE__)
10
+ @icon = File.expand_path("../../img/icon.png", __FILE__)
11
11
  end
12
12
 
13
13
  def run
14
14
  info("Running gitdocs!", "Running gitdocs in `#{@root}'")
15
- @current_remote = sh_string("git config branch.`git branch | grep '^\*' | sed -e 's/\* //'`.remote", "origin")
16
- @current_branch = sh_string("git branch | grep '^\*' | sed -e 's/\* //'", "master")
17
- @current_revision = sh("git rev-parse HEAD").strip rescue nil
15
+ @current_remote = sh_string("git config branch.`git branch | grep '^\*' | sed -e 's/\* //'`.remote", 'origin')
16
+ @current_branch = sh_string("git branch | grep '^\*' | sed -e 's/\* //'", 'master')
17
+ @current_revision = sh_string("git rev-parse HEAD")
18
+
18
19
  mutex = Mutex.new
20
+ # Pull changes from remote repository
19
21
  Thread.new do
20
22
  loop do
21
- mutex.synchronize do
22
- begin
23
- out, status = sh_with_code("git fetch --all && git merge #{@current_remote}/#{@current_branch}")
24
- if status.success?
25
- changes = get_latest_changes
26
- unless changes.empty?
27
- info("Updated with #{changes.size} change#{changes.size == 1 ? '' : 's'}", "`#{@root}' has been updated")
28
- end
29
- else
30
- warn("Error attempting to pull", out)
31
- end
32
- push_changes
33
- rescue Exception
34
- error("There was an error", $!.message) rescue nil
35
- end
36
- end
23
+ mutex.synchronize { sync_changes }
37
24
  sleep @polling_interval
38
25
  end
39
- end
26
+ end.abort_on_exception = true
27
+
28
+ # Listen for changes in local repository
40
29
  listener = FSEvent.new
41
30
  listener.watch(@root) do |directories|
42
31
  directories.uniq!
43
32
  directories.delete_if {|d| d =~ /\/\.git/}
44
33
  unless directories.empty?
45
- mutex.synchronize do
46
- push_changes
47
- end
34
+ mutex.synchronize { push_changes }
48
35
  end
49
36
  end
50
37
  at_exit { listener.stop }
51
38
  listener.run
52
39
  end
53
40
 
41
+ def sync_changes
42
+ out, status = sh_with_code("git fetch --all && git merge #{@current_remote}/#{@current_branch}")
43
+ if status.success?
44
+ changes = get_latest_changes
45
+ unless changes.empty?
46
+ author_list = changes.inject(Hash.new{|h, k| h[k] = 0}) {|h, c| h[c['author']] += 1; h}.to_a.sort{|a,b| b[1] <=> a[1]}.map{|(name, count)| "* #{name} (#{count} change#{count == 1 ? '' : 's'})"}.join("\n")
47
+ info("Updated with #{changes.size} change#{changes.size == 1 ? '' : 's'}", "In `#{@root}':\n#{author_list}")
48
+ end
49
+ push_changes
50
+ elsif out[/CONFLICT/]
51
+ conflicted_files = sh("git ls-files -u --full-name -z").split("\0").
52
+ inject(Hash.new{|h, k| h[k] = []}) {|h, line|
53
+ parts = line.split(/\t/)
54
+ h[parts.last] << parts.first.split(/ /)
55
+ h
56
+ }
57
+ warn("There were some conflicts", "#{conflicted_files.keys.map{|f| "* #{f}"}.join("\n")}")
58
+ conflicted_files.each do |conflict, ids|
59
+ conflict_start, conflict_end = conflict.scan(/(.*?)(|\.[^\.]+)$/).first
60
+ puts "solving #{conflict} with #{ids.inspect}"
61
+ ids.each do |(mode, sha, id)|
62
+ author = " original" if id == "1"
63
+ system("cd #{@root} && git show :#{id}:#{conflict} > '#{conflict_start} (#{sha[0..6]}#{author})#{conflict_end}'")
64
+ end
65
+ system("cd #{@root} && git rm #{conflict}") or raise
66
+ end
67
+ push_changes
68
+ elsif sh_string("git remote").nil? # no remote to pull from
69
+ # Do nothing, no remote repo yet
70
+ else
71
+ error("There was a problem synchronizing this gitdoc", "A problem occurred in #{@root}:\n#{out}")
72
+ end
73
+ end
74
+
54
75
  def push_changes
55
76
  sh 'find . -type d -regex ``./[^.].*'' -empty -exec touch \'{}/.gitignore\' \;'
56
77
  sh 'git add .'
57
78
  # TODO make this message nicer
58
79
  sh "git commit -a -m'Auto-commit from gitdocs'" unless sh("git status -s").strip.empty?
59
- if @current_revision.nil?
80
+ if @current_revision.nil? || sh('git status')[/branch is ahead/]
60
81
  out, code = sh_with_code("git push #{@current_remote} #{@current_branch}")
61
82
  if code.success?
62
83
  changes = get_latest_changes
63
84
  info("Pushed #{changes.size} change#{changes.size == 1 ? '' : 's'}", "`#{@root}' has been pushed")
85
+ elsif @current_revision.nil?
86
+ # ignorable
87
+ elsif out[/\[rejected\]/]
88
+ warn("There was a conflict in #{@root}, retrying", "")
64
89
  else
65
- error("Could not push changes", out)
66
- end
67
- elsif sh('git status')[/branch is ahead/]
68
- out, code = sh_with_code("git push")
69
- if code.success?
70
- changes = get_latest_changes
71
- info("Pushed #{changes.size} change#{changes.size == 1 ? '' : 's'}", "`#{@root}' has been pushed")
72
- else
73
- error("Could not push changes", out)
90
+ error("BAD Could not push changes in #{@root}", out)
91
+ exit
74
92
  end
75
93
  end
76
94
  end
@@ -115,11 +133,10 @@ module Gitdocs
115
133
  else
116
134
  Kernel.warn("#{title}: #{msg}")
117
135
  end
118
- raise
119
136
  end
120
137
 
121
138
  # sh_string("git config branch.`git branch | grep '^\*' | sed -e 's/\* //'`.remote", "origin")
122
- def sh_string(cmd, default)
139
+ def sh_string(cmd, default=nil)
123
140
  val = sh(cmd).strip rescue nil
124
141
  (val.nil? || val.empty?) ? default : val
125
142
  end
@@ -10,17 +10,10 @@ module Gitdocs
10
10
  def start(port = 8888)
11
11
  gds = @gitdocs
12
12
  Thin::Server.start('127.0.0.1', port) do
13
+ use Rack::Static, :urls => ['/css', '/img', '/doc'], :root => File.expand_path("../public", __FILE__)
13
14
  run Renee {
14
15
  if request.path_info == '/'
15
- inline!(<<-EOT, :erb, :locals => {:gds => gds})
16
- <html><body>
17
- <table>
18
- <% gds.each_with_index do |gd, idx| %>
19
- <tr><a href="/<%=idx%>"><%=gd.root%></a></tr>
20
- <% end %>
21
- </table>
22
- </body></html>
23
- EOT
16
+ render! "home", :layout => 'app', :locals => {:gds => gds}
24
17
  else
25
18
  var :int do |idx|
26
19
  gd = gds[idx]
@@ -28,17 +21,23 @@ module Gitdocs
28
21
  expanded_path = File.expand_path(".#{request.path_info}", gd.root)
29
22
  halt 400 unless expanded_path[/^#{Regexp.quote(gd.root)}/]
30
23
  halt 404 unless File.exist?(expanded_path)
24
+ parent = File.dirname(request.path_info)
25
+ parent = '' if parent == '/'
26
+ parent = nil if parent == '.'
27
+ locals = {:idx => idx, :parent => parent, :root => gd.root, :file_path => expanded_path}
31
28
  if File.directory?(expanded_path)
32
- run! Rack::Directory.new(gd.root)
33
- else
34
- begin
35
- render! expanded_path
36
- rescue
37
- run! Rack::File.new(gd.root)
38
- end
29
+ contents = Dir[File.join(gd.root, request.path_info, '*')]
30
+ render! "dir", :layout => 'app', :locals => locals.merge(:contents => contents)
31
+ elsif request.params['mode'] != 'raw' && `file -I #{expanded_path}`.strip.match(%r{text/}) # render file
32
+ contents = Tilt.new(expanded_path).render rescue "<pre>#{File.read(expanded_path)}</pre>"
33
+ render! "file", :layout => 'app', :locals => locals.merge(:contents => contents)
34
+ else # other file
35
+ run! Rack::File.new(gd.root)
39
36
  end
40
37
  end
41
38
  end
39
+ }.setup {
40
+ views_path File.expand_path("../views", __FILE__)
42
41
  }
43
42
  end
44
43
  end
@@ -1,3 +1,3 @@
1
1
  module Gitdocs
2
- VERSION = "0.1.5"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -0,0 +1,9 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Gitdocs #{Gitdocs::VERSION}
5
+ %link{ :href => "/css/reset.css", :rel => "stylesheet" }
6
+ %link{ :href => "/css/app.css", :rel => "stylesheet" }
7
+ %body
8
+ .container
9
+ = preserve(yield)
@@ -0,0 +1,20 @@
1
+ %h1
2
+ =root
3
+
4
+ - if parent
5
+ %a{ :href => parent.empty? ? "/#{idx}" : "/#{idx}#{parent}", :class => "parent" }
6
+ &#8618;
7
+ = parent.empty? ? '/' : parent
8
+ - else
9
+ %a{ :href => "/", :class => "parent" }
10
+ &#8618; Back to selection
11
+
12
+ %h2
13
+ =request.path_info.empty? ? '/' : request.path_info
14
+
15
+ %table
16
+ -contents.each_with_index do |f, i|
17
+ %tr
18
+ %td
19
+ %a{ :href => "/#{idx}#{request.path_info}/#{File.basename(f)}" }
20
+ ="#{request.path_info}/#{File.basename(f)}"
@@ -0,0 +1,18 @@
1
+ %h1
2
+ = root
3
+
4
+ - if parent
5
+ %a{ :href => parent.empty? ? "/#{idx}" : "/#{idx}#{parent}", :class => "parent" }
6
+ &#8618;
7
+ = parent.empty? ? '/' : parent
8
+ - else
9
+ %a{ :href => "/", :class => "parent" }
10
+ &#8618; Back to selection
11
+
12
+ %h2
13
+ = request.path_info.empty? ? '/' : request.path_info
14
+ %a{ :href => "?mode=raw" }
15
+ (raw)
16
+
17
+ .contents
18
+ = preserve contents
@@ -0,0 +1,6 @@
1
+ %table
2
+ -gds.each_with_index do |gd, idx|
3
+ %tr
4
+ %td
5
+ %a{ :href => "/#{idx}" }
6
+ =gd.root
data/test/runner_test.rb CHANGED
@@ -4,10 +4,22 @@ describe "gitdocs runner" do
4
4
  it "should clone files" do
5
5
  with_clones(3) do |clone1, clone2, clone3|
6
6
  File.open(File.join(clone1, "test"), 'w') { |f| f << "testing" }
7
- sleep 2
7
+ sleep 3
8
8
  assert_equal "testing", File.read(File.join(clone1, "test"))
9
9
  assert_equal "testing", File.read(File.join(clone2, "test"))
10
10
  assert_equal "testing", File.read(File.join(clone3, "test"))
11
11
  end
12
12
  end
13
+
14
+ it "should resolve conflicts files" do
15
+ with_clones(3) do |clone1, clone2, clone3|
16
+ File.open(File.join(clone1, "test.txt"), 'w') { |f| f << "testing" }
17
+ sleep 3
18
+ File.open(File.join(clone1, "test.txt"), 'w') { |f| f << "testing\n1" }
19
+ File.open(File.join(clone2, "test.txt"), 'w') { |f| f << "testing\n2" }
20
+ sleep 3
21
+ assert_includes 2..3, Dir[File.join(clone2, "*.txt")].to_a.size
22
+ assert_includes 2..3, Dir[File.join(clone3, "*.txt")].to_a.size
23
+ end
24
+ end
13
25
  end
data/test/test_helper.rb CHANGED
@@ -15,20 +15,23 @@ module Kernel
15
15
  # Redirect standard out, standard error and the buffered logger for sprinkle to StringIO
16
16
  # capture_stdout { any_commands; you_want } => "all output from the commands"
17
17
  def capture_out
18
- old_out, old_err = STDOUT.dup, STDERR.dup
19
- stdout_read, stdout_write = IO.pipe
20
- stderr_read, stderr_write = IO.pipe
21
- $stdout.reopen(stdout_write)
22
- $stderr.reopen(stderr_write)
23
- yield
24
- stdout_write.close
25
- stderr_write.close
26
- out = stdout_read.rewind && stdout_read.read rescue nil
27
- err = stderr_read.rewind && stderr_read.read rescue nil
28
- [out, err]
29
- ensure
30
- $stdout.reopen(old_out)
31
- $stderr.reopen(old_err)
18
+ yield and return if ENV['DEBUG']
19
+ begin
20
+ old_out, old_err = STDOUT.dup, STDERR.dup
21
+ stdout_read, stdout_write = IO.pipe
22
+ stderr_read, stderr_write = IO.pipe
23
+ $stdout.reopen(stdout_write)
24
+ $stderr.reopen(stderr_write)
25
+ yield
26
+ stdout_write.close
27
+ stderr_write.close
28
+ out = stdout_read.rewind && stdout_read.read rescue nil
29
+ err = stderr_read.rewind && stderr_read.read rescue nil
30
+ [out, err]
31
+ ensure
32
+ $stdout.reopen(old_out)
33
+ $stderr.reopen(old_err)
34
+ end
32
35
  end
33
36
  end
34
37
 
@@ -43,10 +46,12 @@ class MiniTest::Spec
43
46
  "/tmp/gitdocs/#{c}"
44
47
  end
45
48
  pids = sub_paths.map { |path| fork do
46
- STDOUT.reopen(File.open("/dev/null", 'w'))
47
- STDERR.reopen(File.open("/dev/null", 'w'))
49
+ unless ENV['DEBUG']
50
+ STDOUT.reopen(File.open("/dev/null", 'w'))
51
+ STDERR.reopen(File.open("/dev/null", 'w'))
52
+ end
48
53
  begin
49
- Gitdocs::Runner.new(path, :growl => false, :polling_interval => 0.1).run
54
+ Gitdocs::Runner.new(path, :growl => false, :polling_interval => 0.5).run
50
55
  rescue
51
56
  puts "RATHER BAD ~~~~~"
52
57
  puts $!.message
@@ -60,6 +65,6 @@ class MiniTest::Spec
60
65
  pids.each { |pid| Process.kill("INT", pid) rescue nil }
61
66
  end
62
67
  ensure
63
- FileUtils.rm_rf("/tmp/gitdocs")
68
+ FileUtils.rm_rf("/tmp/gitdocs") unless ENV['DEBUG']
64
69
  end
65
70
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: gitdocs
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.1.5
5
+ version: 0.2.0
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-01 00:00:00 -08:00
14
+ date: 2011-12-02 00:00:00 -08:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -103,49 +103,60 @@ dependencies:
103
103
  type: :runtime
104
104
  version_requirements: *id008
105
105
  - !ruby/object:Gem::Dependency
106
- name: minitest
106
+ name: haml
107
107
  prerelease: false
108
108
  requirement: &id009 !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: "0"
114
+ type: :runtime
115
+ version_requirements: *id009
116
+ - !ruby/object:Gem::Dependency
117
+ name: minitest
118
+ prerelease: false
119
+ requirement: &id010 !ruby/object:Gem::Requirement
109
120
  none: false
110
121
  requirements:
111
122
  - - ~>
112
123
  - !ruby/object:Gem::Version
113
124
  version: 2.6.1
114
125
  type: :development
115
- version_requirements: *id009
126
+ version_requirements: *id010
116
127
  - !ruby/object:Gem::Dependency
117
128
  name: rake
118
129
  prerelease: false
119
- requirement: &id010 !ruby/object:Gem::Requirement
130
+ requirement: &id011 !ruby/object:Gem::Requirement
120
131
  none: false
121
132
  requirements:
122
133
  - - ">="
123
134
  - !ruby/object:Gem::Version
124
135
  version: "0"
125
136
  type: :development
126
- version_requirements: *id010
137
+ version_requirements: *id011
127
138
  - !ruby/object:Gem::Dependency
128
139
  name: mocha
129
140
  prerelease: false
130
- requirement: &id011 !ruby/object:Gem::Requirement
141
+ requirement: &id012 !ruby/object:Gem::Requirement
131
142
  none: false
132
143
  requirements:
133
144
  - - ">="
134
145
  - !ruby/object:Gem::Version
135
146
  version: "0"
136
147
  type: :development
137
- version_requirements: *id011
148
+ version_requirements: *id012
138
149
  - !ruby/object:Gem::Dependency
139
150
  name: fakeweb
140
151
  prerelease: false
141
- requirement: &id012 !ruby/object:Gem::Requirement
152
+ requirement: &id013 !ruby/object:Gem::Requirement
142
153
  none: false
143
154
  requirements:
144
155
  - - ">="
145
156
  - !ruby/object:Gem::Version
146
157
  version: "0"
147
158
  type: :development
148
- version_requirements: *id012
159
+ version_requirements: *id013
149
160
  description: Open-source Dropbox using Ruby and Git.
150
161
  email:
151
162
  - joshbuddy@gmail.com
@@ -167,9 +178,15 @@ files:
167
178
  - lib/gitdocs.rb
168
179
  - lib/gitdocs/cli.rb
169
180
  - lib/gitdocs/configuration.rb
181
+ - lib/gitdocs/public/css/app.css
182
+ - lib/gitdocs/public/css/reset.css
170
183
  - lib/gitdocs/runner.rb
171
184
  - lib/gitdocs/server.rb
172
185
  - lib/gitdocs/version.rb
186
+ - lib/gitdocs/views/app.haml
187
+ - lib/gitdocs/views/dir.haml
188
+ - lib/gitdocs/views/file.haml
189
+ - lib/gitdocs/views/home.haml
173
190
  - lib/img/icon.png
174
191
  - test/configuration_test.rb
175
192
  - test/runner_test.rb