technomancy-conspire 0.1.0 → 0.1.2
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/History.txt +11 -3
- data/Manifest.txt +1 -0
- data/README.rdoc +22 -19
- data/Rakefile +4 -8
- data/bin/conspire +11 -0
- data/conspire.gemspec +40 -0
- data/lib/conspire.rb +11 -12
- data/lib/conspire/conspirator.rb +12 -14
- data/lib/conspire/gitjour_exts.rb +5 -2
- data/lib/conspire/support/conspire.el +31 -20
- data/test/test_conspire.rb +16 -5
- metadata +5 -4
data/History.txt
CHANGED
@@ -1,6 +1,14 @@
|
|
1
|
-
=== 0.
|
1
|
+
=== 0.1.1 / 2008-07-25
|
2
2
|
|
3
|
-
*
|
3
|
+
* Fixed a bug where empty repositories would not sync.
|
4
|
+
* Lower sync intervals by default.
|
5
|
+
* Emacs support works on a per-buffer basis.
|
4
6
|
|
5
|
-
|
7
|
+
=== 0.1.0 / 2008-07-24
|
8
|
+
|
9
|
+
* Nearly usable! Sorta-works!
|
10
|
+
|
11
|
+
=== 0.0.1 / 2008-07-23
|
12
|
+
|
13
|
+
* Birthday!
|
6
14
|
|
data/Manifest.txt
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
= conspire
|
2
|
-
|
3
|
-
|
2
|
+
|
3
|
+
(c) 2008 Phil Hagelberg
|
4
|
+
http://github.com/technomancy/conspire
|
4
5
|
|
5
6
|
Conspire is a real-time collaborative editing platform using Git as a
|
6
7
|
transport layer.
|
@@ -21,17 +22,18 @@ Once prerequisites are met:
|
|
21
22
|
== Usage
|
22
23
|
|
23
24
|
Conspiracy sessions operate around repositories rather than single
|
24
|
-
files like other collaborative editors.
|
25
|
-
|
26
|
-
|
27
|
-
conspire from there on the files with which you wish to collaborate.
|
28
|
-
|
29
|
-
See lib/conspire/support to see which editors are supported. In Emacs,
|
30
|
-
install conspire.el and then visit the file you want to edit and
|
31
|
-
pressing M-x conspire-mode.
|
25
|
+
files like other collaborative editors. See lib/conspire/support to
|
26
|
+
see which editors are supported. In Emacs, first install conspire.el,
|
27
|
+
then visit the file you want to edit and invoke M-x conspire-mode.
|
32
28
|
|
33
29
|
Repository history is cleared in between conspiracy sessions.
|
34
30
|
|
31
|
+
You can manually use conspire if you want to try it out without an
|
32
|
+
editor. Just launch +conspire+ with a directory as its only argument,
|
33
|
+
and it will initialize a new git repository in there and launch a
|
34
|
+
conspiracy session. You will have to manually "git add" new files you
|
35
|
+
want to introduce to the session.
|
36
|
+
|
35
37
|
For testing purposes, you can run two or more conspiracies on the same
|
36
38
|
machine; you just have to specify an alternate port and name for the
|
37
39
|
others. Names should always include the string "conspiracy" to
|
@@ -45,13 +47,19 @@ Set the DEBUG environment variable to get more information on the console.
|
|
45
47
|
|
46
48
|
* Conflict resolution remains entirely unhandled.
|
47
49
|
|
50
|
+
* Emacs is the only supported editor; see below.
|
51
|
+
|
48
52
|
* When using Avahi for your ZeroConf implementation, you will not be
|
49
53
|
able to do anything unless you have an active network connection. So
|
50
54
|
disconnected conspirancy sessions are not possible without bringing
|
51
55
|
up an ad-hoc network to trick Avahi into activating. You'll also see
|
52
56
|
a big fat warning, which should be ignored.
|
53
57
|
|
54
|
-
==
|
58
|
+
== Contributing
|
59
|
+
|
60
|
+
Patches are welcome via github or email. Adding support for more
|
61
|
+
editors would probably be the most useful contributions, though
|
62
|
+
anything is appreciated.
|
55
63
|
|
56
64
|
Editors must support:
|
57
65
|
|
@@ -59,11 +67,6 @@ Editors must support:
|
|
59
67
|
* Committing files to the repo
|
60
68
|
* Refreshing internal buffers
|
61
69
|
|
62
|
-
Edits should not be allowed in between these steps.
|
63
|
-
|
64
|
-
|
65
|
-
added convenience.
|
66
|
-
|
67
|
-
That's about all there is to it. If your favourite editor is not
|
68
|
-
supported, please fork and add support for it; it's really not a
|
69
|
-
difficult task.
|
70
|
+
Edits should not be allowed in between these steps. Editors may be
|
71
|
+
able to support launching the +conspire+ executable for added
|
72
|
+
convenience.
|
data/Rakefile
CHANGED
@@ -7,17 +7,13 @@ require './lib/conspire.rb'
|
|
7
7
|
Hoe.new('conspire', Conspire::VERSION) do |p|
|
8
8
|
p.developer('Phil Hagelberg', 'technomancy@gmail.com')
|
9
9
|
|
10
|
+
# TODO: tell flog about README.rdoc instead of README.txt
|
10
11
|
p.summary = 'Conspire is a real-time collaborative editing platform using Git as a transport layer.'
|
11
|
-
p.url = 'http://conspire
|
12
|
+
p.url = 'http://github.com/technomancy/conspire'
|
12
13
|
|
14
|
+
# TODO: release on rubyforge once all our required dependency versions make it to rubyforge
|
13
15
|
p.extra_deps << ['technomancy-gitjour', '6.3.0']
|
14
|
-
p.extra_deps << 'clip'
|
15
|
-
end
|
16
|
-
|
17
|
-
desc "Code statistics"
|
18
|
-
task :stats do
|
19
|
-
require 'code_statistics'
|
20
|
-
CodeStatistics.new(['lib'], ['Unit tests', 'test']).to_s
|
16
|
+
p.extra_deps << 'alexvollmer-clip'
|
21
17
|
end
|
22
18
|
|
23
19
|
# vim: syntax=Ruby
|
data/bin/conspire
CHANGED
@@ -9,6 +9,17 @@ options = Clip do |c|
|
|
9
9
|
:default => Conspire::DEFAULTS[:sync_interval])
|
10
10
|
c.optional('n', 'name', :desc => "Session name; must include 'conspiracy'",
|
11
11
|
:default => Conspire::DEFAULTS[:name])
|
12
|
+
c.flag('v', 'version', :desc => 'Print version number and exit')
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: show usage message on --help
|
16
|
+
if !options.valid?
|
17
|
+
puts "Conspire is a git-based collaboration platform."
|
18
|
+
puts " You generally interact use it via an editor; see README for details."
|
19
|
+
abort options.to_s
|
20
|
+
elsif options.version?
|
21
|
+
puts "conspire #{Conspire::VERSION}"
|
22
|
+
exit 0
|
12
23
|
end
|
13
24
|
|
14
25
|
Conspire.start ARGV.first, options
|
data/conspire.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = %q{conspire}
|
3
|
+
s.version = "0.1.2"
|
4
|
+
|
5
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
6
|
+
s.authors = ["Phil Hagelberg"]
|
7
|
+
s.date = %q{2008-08-12}
|
8
|
+
s.default_executable = %q{conspire}
|
9
|
+
s.email = ["technomancy@gmail.com"]
|
10
|
+
s.executables = ["conspire"]
|
11
|
+
s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
|
12
|
+
s.files = ["COPYING", "History.txt", "Manifest.txt", "README.rdoc", "Rakefile", "bin/conspire", "conspire.gemspec", "lib/conspire.rb", "lib/conspire/conspirator.rb", "lib/conspire/gitjour_exts.rb", "lib/conspire/support/conspire.el", "test/perf.rb", "test/test_conspire.rb"]
|
13
|
+
s.has_rdoc = true
|
14
|
+
s.homepage = %q{http://github.com/technomancy/conspire}
|
15
|
+
s.rdoc_options = ["--main", "README.txt"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{conspire}
|
18
|
+
s.rubygems_version = %q{1.2.0}
|
19
|
+
s.summary = %q{Conspire is a real-time collaborative editing platform using Git as a transport layer.}
|
20
|
+
s.test_files = ["test/test_conspire.rb"]
|
21
|
+
|
22
|
+
if s.respond_to? :specification_version then
|
23
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
24
|
+
s.specification_version = 2
|
25
|
+
|
26
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
27
|
+
s.add_runtime_dependency(%q<technomancy-gitjour>, ["= 6.3.0"])
|
28
|
+
s.add_runtime_dependency(%q<alexvollmer-clip>, [">= 0"])
|
29
|
+
s.add_development_dependency(%q<hoe>, [">= 1.7.0"])
|
30
|
+
else
|
31
|
+
s.add_dependency(%q<technomancy-gitjour>, ["= 6.3.0"])
|
32
|
+
s.add_dependency(%q<alexvollmer-clip>, [">= 0"])
|
33
|
+
s.add_dependency(%q<hoe>, [">= 1.7.0"])
|
34
|
+
end
|
35
|
+
else
|
36
|
+
s.add_dependency(%q<technomancy-gitjour>, ["= 6.3.0"])
|
37
|
+
s.add_dependency(%q<alexvollmer-clip>, [">= 0"])
|
38
|
+
s.add_dependency(%q<hoe>, [">= 1.7.0"])
|
39
|
+
end
|
40
|
+
end
|
data/lib/conspire.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
$LOAD_PATH << File.dirname(__FILE__)
|
2
1
|
require 'set'
|
3
2
|
require 'fileutils'
|
4
3
|
|
5
4
|
require 'rubygems'
|
6
5
|
require 'gitjour' # TODO: can we get rid of the avahi compatibility warning?
|
7
6
|
|
8
|
-
require 'conspire/gitjour_exts'
|
9
|
-
require 'conspire/conspirator'
|
7
|
+
require File.dirname(__FILE__) + '/conspire/gitjour_exts'
|
8
|
+
require File.dirname(__FILE__) + '/conspire/conspirator'
|
10
9
|
|
11
10
|
module Conspire
|
12
|
-
VERSION = '0.1.
|
13
|
-
|
14
|
-
|
11
|
+
VERSION = '0.1.2'
|
12
|
+
# TODO: play with optimal intervals; perhaps auto-adjust based on latency?
|
13
|
+
DEFAULTS = { :port => 7456, :name => 'conspiracy', :sync_interval => 0.25 }
|
14
|
+
HOSTNAME = `hostname`.chomp # TODO: is there a better way?
|
15
15
|
|
16
16
|
@conspirators = Set.new
|
17
17
|
|
@@ -19,9 +19,10 @@ module Conspire
|
|
19
19
|
|
20
20
|
# Begin a conspiracy session
|
21
21
|
def start(path, options)
|
22
|
-
@options = options
|
23
|
-
|
22
|
+
@path, @options = path, options
|
23
|
+
|
24
24
|
Gitjour::Application.init @path
|
25
|
+
|
25
26
|
@thread = Thread.new do
|
26
27
|
Gitjour::Application.serve(@path, @options.name, @options.port)
|
27
28
|
end
|
@@ -39,6 +40,7 @@ module Conspire
|
|
39
40
|
end
|
40
41
|
end
|
41
42
|
|
43
|
+
# Sync with all conspirators, dropping the problematic ones
|
42
44
|
def sync_all
|
43
45
|
@conspirators.map do |c|
|
44
46
|
begin
|
@@ -55,9 +57,6 @@ module Conspire
|
|
55
57
|
end
|
56
58
|
|
57
59
|
def discover_loop
|
58
|
-
loop
|
59
|
-
Conspire.discover
|
60
|
-
puts Conspire.conspirators.map{ |c| c.to_s } if ENV['DEBUG']
|
61
|
-
end
|
60
|
+
loop { discover and (p @conspirators if ENV['DEBUG']) }
|
62
61
|
end
|
63
62
|
end
|
data/lib/conspire/conspirator.rb
CHANGED
@@ -1,27 +1,25 @@
|
|
1
1
|
module Conspire
|
2
2
|
class Conspirator
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :host, :port, :name
|
4
4
|
|
5
|
-
def initialize(host, port, name
|
6
|
-
|
5
|
+
def initialize(host, port, name)
|
6
|
+
# host has a trailing dot; remove it
|
7
|
+
@host, @port, @name = host[0 .. -2], port, name
|
7
8
|
end
|
8
9
|
|
9
10
|
def sync(path)
|
10
|
-
# TODO: figure out conflictless rebasing
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
raise "could not rebase from #{url}" if ! success
|
19
|
-
# @last_synced = Time.now # is this useful?
|
11
|
+
# TODO: figure out conflictless rebasing; new content always wins. evan?
|
12
|
+
if ENV['DEBUG']
|
13
|
+
puts "cd #{path} && git pull --rebase #{url}"
|
14
|
+
system "cd #{path} && git pull --rebase #{url}"
|
15
|
+
else
|
16
|
+
system "cd #{path} && git pull --rebase #{url} &> /dev/null"
|
17
|
+
end or raise "could not rebase from #{url}" if ! success
|
20
18
|
end
|
21
19
|
|
22
20
|
def url; "git://#{@host}:#{@port}/" end
|
23
|
-
|
24
21
|
alias_method :to_s, :url
|
22
|
+
alias_method :inspect, :url
|
25
23
|
|
26
24
|
# For set equality
|
27
25
|
def eql?(other); self.url == other.url end
|
@@ -5,9 +5,12 @@ module Gitjour
|
|
5
5
|
|
6
6
|
def init(path)
|
7
7
|
abort "Repository already exists: #{path}" if File.exist? path + '/.git'
|
8
|
-
|
8
|
+
|
9
9
|
`mkdir -p #{path} && cd #{path} && git init`
|
10
|
-
|
10
|
+
FileUtils.touch ["#{path}/.git/git-daemon-export-ok", "#{path}/.conspire"]
|
11
|
+
`cd #{path}; git add .conspire; git commit -m "initial"`
|
12
|
+
|
13
|
+
at_exit { FileUtils.rm_rf [path + '/.git', path + '/.conspire'] } unless ENV['KEEP']
|
11
14
|
end
|
12
15
|
|
13
16
|
def puts(*args); end unless ENV['DEBUG']
|
@@ -3,7 +3,7 @@
|
|
3
3
|
;; Copyright (C) 2008 Phil Hagelberg
|
4
4
|
|
5
5
|
;; Author: Phil Hagelberg <technomancy@gmail.com>
|
6
|
-
;; URL: http://conspire
|
6
|
+
;; URL: http://github.com/technomancy/conspire
|
7
7
|
;; Version: 0.2
|
8
8
|
;; Created: 2008-07-22
|
9
9
|
;; Keywords: collaboration
|
@@ -37,30 +37,22 @@
|
|
37
37
|
;;
|
38
38
|
;; (autoload 'conspire-mode "conspire" "Collaborative editing" t)
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
;;
|
43
|
-
;; Color lines based on which conspirator wrote them?
|
40
|
+
;; TODO: For some reason conspire-sync-buffer only runs on cursor movement
|
41
|
+
;; TODO: Gracefully kill shell process so it can clean up
|
42
|
+
;; TODO: Don't bother with *Async Shell Command* output buffer
|
43
|
+
;; TODO: Color lines based on which conspirator wrote them?
|
44
44
|
|
45
45
|
;;; Code:
|
46
46
|
|
47
|
-
(
|
47
|
+
(defcustom conspire-interval 0.25
|
48
48
|
"Number of seconds to wait before syncing with conspire.")
|
49
49
|
|
50
|
+
(defcustom conspire-arguments ""
|
51
|
+
"Arguments to pass the `conspire' executable, like port, name, etc.")
|
52
|
+
|
50
53
|
(defvar conspire-timer nil
|
51
54
|
"A timer to activate conspire synchronizing.")
|
52
55
|
|
53
|
-
(make-variable-buffer-local 'conspire-mode)
|
54
|
-
|
55
|
-
;;;###autoload
|
56
|
-
(defun conspire-mode ()
|
57
|
-
"Activate conspire-mode for real-time collaborative editing."
|
58
|
-
(interactive)
|
59
|
-
(setq conspire-mode t)
|
60
|
-
(setq conspire-timer
|
61
|
-
(run-with-idle-timer conspire-interval :repeat 'conspire-sync-buffer)))
|
62
|
-
|
63
|
-
|
64
56
|
(defun conspire-sync-buffer ()
|
65
57
|
"Synchronize buffer with Conspire repository."
|
66
58
|
(when conspire-mode
|
@@ -68,8 +60,27 @@
|
|
68
60
|
(save-buffer)
|
69
61
|
(shell-command (format "git add %s && git commit -m \"conspire\""
|
70
62
|
buffer-file-name)))
|
71
|
-
(revert-buffer nil t)
|
72
|
-
|
73
|
-
(
|
63
|
+
(revert-buffer nil t) ;; revert resets local variables; heh
|
64
|
+
(cancel-timer conspire-timer)
|
65
|
+
(conspire-mode t)))
|
66
|
+
|
67
|
+
;;;###autoload
|
68
|
+
(define-minor-mode conspire-mode
|
69
|
+
"Toggle conspire-mode for real-time collaborative editing.
|
70
|
+
|
71
|
+
If the current buffer isn't part of a conspiracy session, a new
|
72
|
+
session will be started."
|
73
|
+
:lighter "-conspire"
|
74
|
+
(unless (file-exists-p (concat (file-name-directory buffer-file-name)
|
75
|
+
".conspire"))
|
76
|
+
(save-window-excursion
|
77
|
+
(shell-command (format "conspire %s %s >& /dev/null &"
|
78
|
+
(file-name-directory buffer-file-name)
|
79
|
+
conspire-arguments))))
|
80
|
+
(setq conspire-timer
|
81
|
+
(or conspire-timer
|
82
|
+
(run-with-idle-timer conspire-interval :repeat
|
83
|
+
'conspire-sync-buffer))))
|
74
84
|
|
85
|
+
(provide 'conspire)
|
75
86
|
;;; conspire.el ends here
|
data/test/test_conspire.rb
CHANGED
@@ -25,12 +25,12 @@ class TestConspire < Test::Unit::TestCase
|
|
25
25
|
def setup
|
26
26
|
Gitjour::Application.init(REMOTE_SPACE)
|
27
27
|
File.open(REMOTE_SPACE + '/file', 'w') { |f| f.puts "hello world." }
|
28
|
-
`cd #{REMOTE_SPACE}; git add file; git commit -m "
|
28
|
+
`cd #{REMOTE_SPACE}; git add file; git commit -m "conspire"`
|
29
29
|
|
30
30
|
@remote_thread = Thread.new do
|
31
31
|
Gitjour::Application.serve(REMOTE_SPACE, 'conspiracy-remote-test', 7458)
|
32
32
|
end
|
33
|
-
|
33
|
+
@remote = Conspire::Conspirator.new('localhost.', '7458', 'conspiracy')
|
34
34
|
Conspire.start(LOCAL_SPACE, OpenStruct.new(:port => 7457,
|
35
35
|
:name => 'conspiracy',
|
36
36
|
:sync_interval => 0.5))
|
@@ -55,14 +55,25 @@ class TestConspire < Test::Unit::TestCase
|
|
55
55
|
|
56
56
|
def test_sync
|
57
57
|
# getting random unreproducible failings here
|
58
|
-
Conspire.conspirators <<
|
58
|
+
Conspire.conspirators << @remote
|
59
59
|
Conspire.sync_all
|
60
60
|
assert_equal ["#{LOCAL_SPACE}/file"], Dir.glob("#{LOCAL_SPACE}/*")
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_conspirator_set
|
64
|
-
Conspire.conspirators << Conspire::Conspirator.new('dynabook.', '7458')
|
65
|
-
Conspire.conspirators << Conspire::Conspirator.new('dynabook.', '7458')
|
64
|
+
Conspire.conspirators << Conspire::Conspirator.new('dynabook.', '7458', 'conspiracy')
|
65
|
+
Conspire.conspirators << Conspire::Conspirator.new('dynabook.', '7458', 'conspiracy')
|
66
66
|
assert_equal 1, Conspire.conspirators.size
|
67
67
|
end
|
68
|
+
|
69
|
+
def test_conflicts
|
70
|
+
@remote.sync(LOCAL_SPACE)
|
71
|
+
assert File.exist?(LOCAL_SPACE + '/file'), "Sync did not pull in file"
|
72
|
+
assert_equal 'hello world.\n', File.read(LOCAL_SPACE + '/file')
|
73
|
+
|
74
|
+
File.open("#{LOCAL_SPACE}/file", 'w') { |f| f.puts "hello conspirators!" }
|
75
|
+
`cd #{LOCAL_SPACE}; git add file; git commit -m "conspire"`
|
76
|
+
@remote.sync(LOCAL_SPACE)
|
77
|
+
assert_equal 'hello conspirators!\n', File.read(LOCAL_SPACE + '/file')
|
78
|
+
end
|
68
79
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: technomancy-conspire
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phil Hagelberg
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-08-12 00:00:00 -07:00
|
13
13
|
default_executable: conspire
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
version: 6.3.0
|
23
23
|
version:
|
24
24
|
- !ruby/object:Gem::Dependency
|
25
|
-
name: clip
|
25
|
+
name: alexvollmer-clip
|
26
26
|
version_requirement:
|
27
27
|
version_requirements: !ruby/object:Gem::Requirement
|
28
28
|
requirements:
|
@@ -56,6 +56,7 @@ files:
|
|
56
56
|
- README.rdoc
|
57
57
|
- Rakefile
|
58
58
|
- bin/conspire
|
59
|
+
- conspire.gemspec
|
59
60
|
- lib/conspire.rb
|
60
61
|
- lib/conspire/conspirator.rb
|
61
62
|
- lib/conspire/gitjour_exts.rb
|
@@ -63,7 +64,7 @@ files:
|
|
63
64
|
- test/perf.rb
|
64
65
|
- test/test_conspire.rb
|
65
66
|
has_rdoc: true
|
66
|
-
homepage: http://conspire
|
67
|
+
homepage: http://github.com/technomancy/conspire
|
67
68
|
post_install_message:
|
68
69
|
rdoc_options:
|
69
70
|
- --main
|