v 0.0.4

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.
Files changed (47) hide show
  1. data/.document +5 -0
  2. data/.gitignore +23 -0
  3. data/.watchr +24 -0
  4. data/.yardoc +0 -0
  5. data/LICENSE +20 -0
  6. data/README.markdown +146 -0
  7. data/Rakefile +56 -0
  8. data/VERSION +1 -0
  9. data/auto_commit.rb +131 -0
  10. data/lib/v/adapters/git/branches.rb +115 -0
  11. data/lib/v/adapters/git/commits.rb +55 -0
  12. data/lib/v/adapters/git/environment.rb +99 -0
  13. data/lib/v/adapters/git/index.rb +63 -0
  14. data/lib/v/adapters/git/object.rb +104 -0
  15. data/lib/v/adapters/git/object_types/blob.rb +24 -0
  16. data/lib/v/adapters/git/object_types/commit.rb +124 -0
  17. data/lib/v/adapters/git/object_types/tag.rb +23 -0
  18. data/lib/v/adapters/git/object_types/tree.rb +51 -0
  19. data/lib/v/adapters/git/operations/add_to_index.rb +30 -0
  20. data/lib/v/adapters/git/operations/branch.rb +42 -0
  21. data/lib/v/adapters/git/operations/commit_index.rb +39 -0
  22. data/lib/v/adapters/git/operations/diff_index.rb +20 -0
  23. data/lib/v/adapters/git/operations/initialize_repository.rb +21 -0
  24. data/lib/v/adapters/git/operations/list_files.rb +38 -0
  25. data/lib/v/adapters/git/operations/list_tree.rb +30 -0
  26. data/lib/v/adapters/git/operations/push_references_to_remote.rb +25 -0
  27. data/lib/v/adapters/git/operations/remove_from_index.rb +25 -0
  28. data/lib/v/adapters/git/operations/reset_index.rb +25 -0
  29. data/lib/v/adapters/git/operations/show_log.rb +23 -0
  30. data/lib/v/adapters/git/operations/show_object.rb +21 -0
  31. data/lib/v/adapters/git/operations/tag.rb +29 -0
  32. data/lib/v/adapters/git/participation.rb +18 -0
  33. data/lib/v/adapters/git/remotes.rb +19 -0
  34. data/lib/v/adapters/git/status.rb +60 -0
  35. data/lib/v/adapters/git.rb +27 -0
  36. data/lib/v/adapters.rb +25 -0
  37. data/lib/v/arguments.rb +102 -0
  38. data/lib/v/errors.rb +39 -0
  39. data/lib/v/future.rb +46 -0
  40. data/lib/v/operation.rb +94 -0
  41. data/lib/v/worker.rb +73 -0
  42. data/lib/v.rb +29 -0
  43. data/test/teststrap.rb +4 -0
  44. data/test/v_test.rb +32 -0
  45. data/test/work_tree/file +1 -0
  46. data/v.gemspec +97 -0
  47. metadata +131 -0
@@ -0,0 +1,63 @@
1
+ module V
2
+ module Adapters
3
+ module Git
4
+ # http://book.git-scm.com/7_the_git_index.html
5
+ class Index
6
+ include V::Adapters::Git
7
+
8
+ def initialize(environment)
9
+ @environment = environment
10
+ end
11
+
12
+ def add(*files)
13
+ @environment.add *files
14
+ end
15
+ alias_method :<<, :add
16
+
17
+ def include?(filename)
18
+ @environment.ls_files(filename) !~ /^\s*$/
19
+ end
20
+
21
+ def +(other)
22
+ raise NotImplementedError, 'TODO: implement Index#+(other)'
23
+ end
24
+
25
+ def -(other)
26
+ other.is_a? Git::Object or
27
+ raise ArgumentError, 'expected Git::Object'
28
+
29
+ name = case other
30
+ when Commit
31
+ other.name
32
+ when Tree
33
+ other.name
34
+ when Tag
35
+ other.name
36
+ when Blob
37
+ raise NotImplementedError, 'TODO: implement Index#-(other)'
38
+ else raise p(other)
39
+ end
40
+
41
+ @environment.diff_index name,
42
+ :name_status => true, :cached => true do |out, err|
43
+ Status.new out
44
+ end
45
+ end
46
+
47
+ def commit(*args)
48
+ @environment.commit *args
49
+ end
50
+ def reset(*args)
51
+ @environment.reset *args
52
+ end
53
+
54
+ protected
55
+
56
+ def assign(attrs)
57
+ attrs.each { |k, v| instance_variable_set :"@#{ k }", v }
58
+ end
59
+
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,104 @@
1
+ module V
2
+ module Adapters
3
+ module Git
4
+ class ObjectType
5
+ include Singleton
6
+
7
+ # Returns true if other is a Git::Object and has the same type, false
8
+ # otherwise.
9
+ def ===(object)
10
+ object.is_a? Git::Object and object.type == self
11
+ end
12
+
13
+ # See ObjectType#===.
14
+ def self.===(object)
15
+ instance === object
16
+ end
17
+
18
+ def content(object)
19
+ raise NotImplementedError
20
+ end
21
+ def to_s(object = nil)
22
+ object ? object.name : self.class.name
23
+ end
24
+ end
25
+
26
+ # http://book.git-scm.com/1_the_git_object_model.html
27
+ class Object
28
+
29
+ DEFN = 'def %s(*args, &block) type.%s self, *args, &block end'
30
+ def self.register_methods(*methods)
31
+ methods.each { |method| class_eval DEFN.gsub('%s', method.to_s) }
32
+ end
33
+ @@types = {}
34
+ def self.register_type(type)
35
+ @@types.update type
36
+ end
37
+
38
+ attr_reader :name, :environment
39
+
40
+ def initialize(environment, attrs)
41
+ @environment = environment
42
+ assign attrs
43
+ end
44
+
45
+ # Keep this lazy! Most objects only need a name.
46
+ def type
47
+ @@types.fetch @type
48
+ end
49
+
50
+ # Content depends on type. Since this object is typecasted on demand
51
+ # content can be assigned during initialize (e.g. after commit).
52
+ def content(reload = false)
53
+ @content = type.content self if reload or not defined? @content
54
+ @content
55
+ end
56
+ def size
57
+ content.size
58
+ end
59
+ alias_method :length, :size
60
+
61
+ def to_s
62
+ type.to_s self
63
+ end
64
+
65
+ INSPECT_EXCLUDES = [:'@content', :'@name', :'@type']
66
+ def inspect
67
+ attrs = instance_variables.inject([]) { |m, i|
68
+ if INSPECT_EXCLUDES.include? :"#{ i }" then m
69
+ else
70
+ m << "#{ i }=#{ instance_variable_get(:"#{ i }").inspect }"
71
+ end
72
+ } * ' '
73
+ type = "#{ @type }".capitalize
74
+
75
+ "#<Git::#{ type }:#{ @name } #{ attrs } @content=[...]>"
76
+ end
77
+
78
+ # Returns the path to the object in the current root.
79
+ def path(*basenames)
80
+ type.path @parent, @basenames, *basenames
81
+ end
82
+
83
+ # Returns true if the other object has the same type and name, false
84
+ # otherwise.
85
+ def ==(other)
86
+ type === other and name == other.name
87
+ end
88
+
89
+ protected
90
+
91
+ def assign(attrs)
92
+ attrs.each { |k, v| instance_variable_set :"@#{ k }", v }
93
+ end
94
+
95
+ end
96
+ end
97
+ end
98
+ end
99
+
100
+ begin
101
+ __dir__ = File.dirname __FILE__
102
+ %w[ commit tree blob tag ].
103
+ each { |basename| require "#{ __dir__ }/object_types/#{ basename }" }
104
+ end
@@ -0,0 +1,24 @@
1
+ module V
2
+ module Adapters
3
+ module Git
4
+ class Blob < ObjectType
5
+
6
+ def content(object)
7
+ object.environment.show object.name, :pretty => :raw
8
+ end
9
+
10
+ def path(parent, basename)
11
+ parent.path basename
12
+ end
13
+
14
+ def [](object, *args)
15
+ object.content[*args]
16
+ end
17
+
18
+ Object.register_type :blob => instance
19
+ Object.register_methods :[]
20
+
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,124 @@
1
+ module V
2
+ module Adapters
3
+ module Git
4
+ class Commit < ObjectType
5
+
6
+ # Completes :name in <tt>attrs</tt> and returns a Git::Object with
7
+ # type :commit.
8
+ def self.with(environment, attrs = {})
9
+ if attrs[:name].length < 40
10
+ glob = File.join environment.git_dir, 'objects',
11
+ attrs[:name][0, 2], "#{ attrs[:name][2, 38] }*"
12
+
13
+ attrs[:name] = attrs[:name][0, 2] + File.basename(Dir[ glob ].first)
14
+ end
15
+
16
+ Object.new environment, attrs.update(:type => :commit)
17
+ end
18
+
19
+ # see `git help show` for details
20
+ F = {
21
+ :commit_hash => '%H',
22
+ :commit_hash_abbrev => '%h',
23
+ :tree_hash => '%T', #
24
+ :tree_hash_abbrev => '%t',
25
+ :parent_hashes => '%P', #
26
+ :parent_hashes_abbrev => '%p',
27
+ :a_name => '%an', #
28
+ :a_name_mailmap => '%aN',
29
+ :a_email => '%ae', #
30
+ :a_email_mailmap => '%aE',
31
+ :a_date => '%ad',
32
+ :a_date_rfc2822 => '%aD',
33
+ :a_date_relative => '%ar',
34
+ :a_date_unix => '%at', #
35
+ :a_date_iso8601 => '%ai',
36
+ :c_name => '%cn', #
37
+ :c_name_mailmap => '%cN',
38
+ :c_email => '%ce', #
39
+ :c_email_mailmap => '%cE',
40
+ :c_date => '%cd',
41
+ :c_date_rfc2822 => '%cD',
42
+ :c_date_relative => '%cr',
43
+ :c_date_unix => '%ct', #
44
+ :c_date_iso8601 => '%ci',
45
+ :ref_names => '%d',
46
+ :encoding => '%e',
47
+ :subject => '%s', #
48
+ :subject_sanitized => '%f',
49
+ :body => '%b', # extra
50
+ :red => '%Cred',
51
+ :green => '%Cgreen',
52
+ :blue => '%Cblue',
53
+ :reset_color => '%Creset',
54
+ :newline => '%n',
55
+ :hex => '%%x%02x'
56
+ # o %m: left, right or boundary mark
57
+ # o %C(...): color specification, as described in color.branch.* config option
58
+ }
59
+ format = []
60
+ format<< F[:tree_hash]
61
+ format<< F[:parent_hashes]
62
+ format<< F.values_at(:a_name, :a_email, :a_date_unix) * (F[:hex] % 0)
63
+ format<< F.values_at(:c_name, :c_email, :c_date_unix) * (F[:hex] % 0)
64
+ format<< F.values_at(:subject, :body) * (F[:hex] % 0)
65
+ FORMAT = format * F[:newline]
66
+
67
+ def content(object)
68
+ object.environment.show object.name, :pretty => FORMAT
69
+ end
70
+
71
+ def tree(object)
72
+ fetch object, :tree
73
+ end
74
+ def parents(object)
75
+ fetch object, :parents
76
+ end
77
+ def author(object)
78
+ fetch object, :author
79
+ end
80
+ def committer(object)
81
+ fetch object, :commiter
82
+ end
83
+ def subject(object)
84
+ fetch object, :subject
85
+ end
86
+ def body(object)
87
+ fetch object, :body
88
+ end
89
+
90
+ def path(parent, *basenames)
91
+ basenames.compact * '/'
92
+ end
93
+
94
+ protected
95
+
96
+ def fetch(object, attribute)
97
+ content = object.content.split "\n", 5
98
+ env = object.environment
99
+
100
+ case attribute
101
+ when :tree
102
+ Tree.with env, :name => content[0], :parent => object
103
+ when :parents
104
+ content[1].split(' ').
105
+ inject({}) { |mem, name| mem.update name => Commit.with(env, :name => name) }
106
+ when :author
107
+ Participation.new :author, *content[2].split("\0")
108
+ when :commiter
109
+ Participation.new :committer, *content[3].split("\0")
110
+ when :subject
111
+ content[4].split("\0").first
112
+ when :body
113
+ content[4].split("\0").last
114
+ end
115
+ end
116
+
117
+ Object.register_type :commit => instance
118
+ Object.register_methods :tree, :parents, :author, :committer,
119
+ :subject, :body
120
+
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,23 @@
1
+ module V
2
+ module Adapters
3
+ module Git
4
+ class Tag < ObjectType
5
+
6
+ # Returns the name of the commit the object points to.
7
+ def content(obj)
8
+ path = File.join obj.environment.git_dir, %w[ refs tags ], obj.name
9
+ File.read(path).chomp
10
+ end
11
+
12
+ # Returns the commit the object points to.
13
+ def commit(object)
14
+ Commit.with object.environment, :name => object.content
15
+ end
16
+
17
+ Object.register_type :tag => instance
18
+ Object.register_methods :commit
19
+
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ module V
2
+ module Adapters
3
+ module Git
4
+ class Tree < ObjectType
5
+ include Enumerable
6
+
7
+ def self.with(environment, attrs = {})
8
+ Object.new environment, attrs.update(:type => :tree)
9
+ end
10
+
11
+ LINE_RE = /^(\d{6}) (blob|tree) ([[:alnum:]]{40})\t(.+)$/
12
+ def content(object)
13
+ environment, name, parent = object.environment, object.name, object
14
+
15
+ environment.ls_tree(name).split($/).
16
+ inject({}) do |mem, line|
17
+ mode, type, name, basename = LINE_RE.match(line).captures
18
+
19
+ # see git help ls-tree
20
+ # path.gsub! /(\\n|\\t|\\)/, ...
21
+
22
+ child = Object.new environment,
23
+ :type => type.to_sym, :name => name,
24
+ :parent => parent, :basename => basename
25
+
26
+ mem.update basename => child
27
+ end
28
+ end
29
+ def each(object)
30
+ object.content.values.each { |v| yield v }
31
+ end
32
+
33
+ def [](object, glob)
34
+ raise NotImplementedError
35
+ end
36
+ def /(object, path)
37
+ parts = path.to_s.split '/'
38
+ parts.inject(object) { |obj, name| obj.content.fetch name }
39
+ end
40
+
41
+ def path(parent, *basenames)
42
+ parent.path *basenames
43
+ end
44
+
45
+ Object.register_type :tree => instance
46
+ Object.register_methods :each, :/, :[]
47
+
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,30 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ AddToIndex = operation(:add) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.dry_run.n
7
+ args.verbose.v
8
+ args.force.f
9
+ args.interactive.i
10
+ args.patch.p
11
+ args.edit.e
12
+ args.all.A
13
+ args.update.u
14
+ args.intent_to_add.N
15
+ args.refresh
16
+ args.ignore_errors
17
+ args << '--'
18
+ end
19
+
20
+ include WorkTreeRequirement
21
+ def run(environment)
22
+ out, err = exec environment
23
+ err.empty? or raise V::ERROR, err
24
+
25
+ Index.new environment
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,42 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ Branch = operation(:branch) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.color
7
+ args.no_color
8
+ args.remote(:alias => true).r
9
+ args.all(:alias => true).a
10
+ args.verbose.v
11
+ args.abbrev(7)
12
+ args.no_abbrev
13
+ args.merged
14
+ args.no_merged
15
+ args.contains
16
+ # <commit>
17
+ args.track
18
+ args.no_track
19
+ args.reflog(:alias => true).l
20
+ args.force(:alias => true).f
21
+ # <branchname>
22
+ # <startpoint>
23
+ args.move(:alias => true).m
24
+ args.move!(:alias => true).M
25
+ # <oldbranch>
26
+ # <newbranch>
27
+ args.delete(:alias => true).d
28
+ args.delete!(:alias => true).D
29
+ # <branchname>
30
+ end
31
+
32
+ include WorkTreeRequirement
33
+ def run(environment)
34
+ out, err = exec environment
35
+ err.empty? or raise V::ERROR, err
36
+
37
+ out
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,39 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ CommitIndex = operation(:commit) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.all.a
7
+ args.interactive
8
+ args.signoff.s
9
+ args.verbose.v
10
+ args.untracked_files(:all).u
11
+ args.amend
12
+ args.reedit_message(nil).c
13
+ args.reuse_message(nil).C
14
+ args.file(nil).F
15
+ args.message(nil, :first => true).m
16
+ args.allow_empty
17
+ args.no_verify.n
18
+ args.edit.e
19
+ args.author nil
20
+ args.cleanup :default
21
+ args << '--'
22
+ args.include.i
23
+ args.only.o
24
+ end
25
+
26
+ include WorkTreeRequirement
27
+ def run(environment)
28
+ out, err = exec environment
29
+ err.empty? or raise V::ERROR, err
30
+
31
+ name = /^\[(?:.*) (\S+)\]/.match(out).captures.first
32
+ Commit.with environment, :name => name
33
+ rescue
34
+ return out
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,20 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ DiffIndex = operation(:diff_index) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ # TODO: complete arguments ...
7
+ args.cached
8
+ args.name_status
9
+ end
10
+
11
+ def run(environment)
12
+ out, err = exec environment
13
+ err.empty? or raise V::ERROR, err
14
+
15
+ out
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ InitializeRepository = operation(:init) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.quiet.q
7
+ args.bare
8
+ args.template(nil)
9
+ args.shared(:umask, false)
10
+ end
11
+
12
+ def run(environment)
13
+ out, err = exec environment
14
+ err.empty? or raise V::ERROR, err
15
+
16
+ environment
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,38 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ ListFiles = operation(:ls_files) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.zero(:alias => true).z
7
+ args.tags(:alias => true).t
8
+ # TODO: understand v option
9
+ args.vulgar(:alias => true).v
10
+ args.cached.c
11
+ args.deleted.d
12
+ args.others.o
13
+ args.ignored.i
14
+ args.stage.s
15
+ args.unmerge.u
16
+ args.killed.k
17
+ args.modified.m
18
+ args.exclude(nil).x
19
+ args.exclude_from(nil).X
20
+ args.exclude_per_directory(nil)
21
+ args.exclude_standard
22
+ args.error_unmatch
23
+ args.with_tree(nil)
24
+ args.full_name
25
+ args.abbrev(40)
26
+ args << '--'
27
+ end
28
+
29
+ def run(environment)
30
+ out, err = exec environment
31
+ err.empty? or raise V::ERROR, err
32
+
33
+ out
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,30 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ ListTree = operation(:ls_tree) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ # TODO: check naming
7
+ args.directories(:alias => true).d
8
+ args.recursive(:alias => true).r
9
+ # TODO: check naming
10
+ args.trace(:alias => true).t
11
+ args.long.l
12
+ args.zero(:alias => true).z
13
+ args.name_only
14
+ # TODO: implement support for non abbrev aliases
15
+ args.name_status
16
+ args.abbrev(40)
17
+ args.full_name
18
+ args.full_tree
19
+ end
20
+
21
+ def run(environment)
22
+ out, err = exec environment
23
+ err.empty? or raise V::ERROR, err
24
+
25
+ out
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ PushReferencesToRemote = operation(:push) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.all
7
+ args.mirror
8
+ args.tags
9
+ args.dry_run
10
+ args.porcelain
11
+ args.receive_pack nil
12
+ args.repository nil
13
+ args.thin
14
+ args.no_thin
15
+ args.force.f
16
+ args.verbose.v
17
+ end
18
+
19
+ def run(environment)
20
+ exec environment
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ RemoveFromIndex = operation(:rm) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.force.f
7
+ args.dry_run.n
8
+ args.recursive(:alias => true).r
9
+ args.cached
10
+ args.ignore_unmatch
11
+ args.quiet.q
12
+ args << '--'
13
+ end
14
+
15
+ include WorkTreeRequirement
16
+ def run(environment)
17
+ out, err = exec environment
18
+ err.empty? or raise V::ERROR, err
19
+
20
+ Index.new environment
21
+ end
22
+
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module V::Adapters::Git
2
+ module Operations
3
+ ResetIndex = operation(:reset) do
4
+ # 1.6.3.2
5
+ arguments do |args|
6
+ args.mixed
7
+ args.soft
8
+ args.hard
9
+ args.merged
10
+ args.quiet(:alias => true).q
11
+ args.commit(:HEAD, :rude => true).c
12
+ args << '--'
13
+ end
14
+
15
+ include WorkTreeRequirement
16
+ def run(environment)
17
+ out, err = exec environment
18
+ err.empty? or raise V::ERROR, err
19
+
20
+ Index.new environment
21
+ end
22
+
23
+ end
24
+ end
25
+ end