hglib 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.md +27 -0
- data/README.md +15 -7
- data/lib/hglib.rb +47 -2
- data/lib/hglib/config.rb +60 -0
- data/lib/hglib/mixins.rb +77 -0
- data/lib/hglib/repo.rb +187 -16
- data/lib/hglib/repo/bookmark.rb +74 -0
- data/lib/hglib/repo/id.rb +38 -24
- data/lib/hglib/repo/log_entry.rb +12 -12
- data/lib/hglib/repo/tag.rb +52 -0
- data/lib/hglib/server.rb +23 -6
- data/spec/hglib/config_spec.rb +36 -0
- data/spec/hglib/mixins_spec.rb +80 -0
- data/spec/hglib/repo/id_spec.rb +69 -107
- data/spec/hglib/repo/log_entry_spec.rb +12 -12
- data/spec/hglib/repo_spec.rb +245 -51
- data/spec/hglib_spec.rb +43 -1
- data/spec/spec_helper.rb +7 -2
- metadata +22 -85
- metadata.gz.sig +0 -0
- data/.simplecov +0 -9
- data/ChangeLog +0 -128
- data/Manifest.txt +0 -22
- data/Rakefile +0 -99
- data/examples/clone.rb +0 -13
- data/integration/commands/clone_spec.rb +0 -52
- data/integration/spec_helper.rb +0 -29
- data/spec/.status +0 -42
@@ -0,0 +1,74 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'loggability'
|
5
|
+
require 'hglib/repo' unless defined?( Hglib::Repo )
|
6
|
+
require 'hglib/mixins'
|
7
|
+
|
8
|
+
|
9
|
+
class Hglib::Repo::Bookmark
|
10
|
+
extend Loggability,
|
11
|
+
Hglib::MethodUtilities
|
12
|
+
|
13
|
+
|
14
|
+
# Send logs to Hglib's logger
|
15
|
+
log_to :hglib
|
16
|
+
|
17
|
+
|
18
|
+
# {
|
19
|
+
# "active" => true,
|
20
|
+
# "bookmark" => "master",
|
21
|
+
# "node" => "720c115412188539039b87baf57931fb5415a0bf",
|
22
|
+
# "rev" => 26
|
23
|
+
# }
|
24
|
+
|
25
|
+
### Create a new Bookmark with the given values.
|
26
|
+
def initialize( repo, bookmark:, node:, rev:, active: false )
|
27
|
+
@repo = repo
|
28
|
+
@name = bookmark
|
29
|
+
@node = node
|
30
|
+
@rev = rev
|
31
|
+
@active = active
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
######
|
36
|
+
public
|
37
|
+
######
|
38
|
+
|
39
|
+
##
|
40
|
+
# The Hglib::Repo the bookmark lives in
|
41
|
+
attr_reader :repo
|
42
|
+
|
43
|
+
##
|
44
|
+
# The name of the bookmark
|
45
|
+
attr_reader :name
|
46
|
+
|
47
|
+
##
|
48
|
+
# The SHA of the commit the bookmark is currently on
|
49
|
+
attr_reader :node
|
50
|
+
|
51
|
+
##
|
52
|
+
# The revision number of the commit the bookmark is currently on
|
53
|
+
attr_reader :rev
|
54
|
+
|
55
|
+
##
|
56
|
+
# Whether or not the bookmark is currently active
|
57
|
+
attr_predicate :active
|
58
|
+
|
59
|
+
|
60
|
+
### Delete the bookmark from its repository.
|
61
|
+
def delete
|
62
|
+
return self.repo.bookmark( self.name, delete: true )
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
### Move the bookmark to the specified +revision+.
|
67
|
+
def move_to( revision )
|
68
|
+
return self.repo.bookmark( self.name, rev: revision, force: true )
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
end # class Hglib::Repo::Bookmark
|
73
|
+
|
74
|
+
|
data/lib/hglib/repo/id.rb
CHANGED
@@ -2,34 +2,36 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'hglib/repo' unless defined?( Hglib::Repo )
|
5
|
+
require 'hglib/mixins'
|
5
6
|
|
6
7
|
|
7
8
|
# The identification of a particular revision of a repository.
|
8
9
|
class Hglib::Repo::Id
|
10
|
+
extend Hglib::MethodUtilities
|
9
11
|
|
10
|
-
### Parse the given +raw_id+ and return a new Id that contains the parsed
|
11
|
-
### information.
|
12
|
-
def self::parse( raw_id )
|
13
|
-
global, tags, bookmarks = raw_id.chomp.split( ' ', 3 )
|
14
|
-
has_plus = global.chomp!( '+' ) ? true : false
|
15
12
|
|
16
|
-
|
17
|
-
|
13
|
+
# The SHA of the zeroth node
|
14
|
+
DEFAULT_ID = '0000000000000000000000000000000000000000'
|
18
15
|
|
19
|
-
|
20
|
-
|
16
|
+
# The default branch name to use
|
17
|
+
DEFAULT_BRANCH = 'default'
|
21
18
|
|
22
|
-
|
23
|
-
|
19
|
+
# The SHA of the node when the repo is at tip
|
20
|
+
DEFAULT_NODE = 'ffffffffffffffffffffffffffffffffffffffff'
|
24
21
|
|
25
22
|
|
26
23
|
### Create a new repository ID with the given +global+ revision identifier, one
|
27
24
|
### or more +tags+, and other options.
|
28
|
-
def initialize(
|
29
|
-
|
30
|
-
|
25
|
+
def initialize( id:, branch: DEFAULT_BRANCH, node: DEFAULT_NODE, dirty: false,
|
26
|
+
parents: [], tags: [], bookmarks: [] )
|
27
|
+
|
28
|
+
@id = id[ /\p{XDigit}{40}/ ]
|
29
|
+
@branch = branch
|
30
|
+
@node = node
|
31
|
+
@dirty = dirty == '+'
|
32
|
+
@tags = Array( tags )
|
33
|
+
@parents = Array( parents )
|
31
34
|
@bookmarks = Array( bookmarks )
|
32
|
-
@uncommitted_changes = uncommitted_changes
|
33
35
|
end
|
34
36
|
|
35
37
|
|
@@ -38,8 +40,27 @@ class Hglib::Repo::Id
|
|
38
40
|
######
|
39
41
|
|
40
42
|
##
|
41
|
-
# The
|
42
|
-
attr_reader :
|
43
|
+
# The long-form revision ID
|
44
|
+
attr_reader :id
|
45
|
+
alias_method :global, :id
|
46
|
+
|
47
|
+
##
|
48
|
+
# The name of the current branch
|
49
|
+
attr_reader :branch
|
50
|
+
|
51
|
+
##
|
52
|
+
# The ID of the current
|
53
|
+
attr_reader :node
|
54
|
+
|
55
|
+
##
|
56
|
+
# The current IDs of the current revision's parent(s).
|
57
|
+
attr_reader :parents
|
58
|
+
|
59
|
+
##
|
60
|
+
# Does the repo have uncommitted changes?
|
61
|
+
attr_predicate :dirty
|
62
|
+
alias_method :uncommitted_changes?, :dirty?
|
63
|
+
alias_method :has_uncommitted_changes?, :dirty?
|
43
64
|
|
44
65
|
##
|
45
66
|
# The tags belonging to the revision of the repo.
|
@@ -50,13 +71,6 @@ class Hglib::Repo::Id
|
|
50
71
|
attr_reader :bookmarks
|
51
72
|
|
52
73
|
|
53
|
-
### Returns +true+ if the repo's working directory has uncommitted changes.
|
54
|
-
def uncommitted_changes?
|
55
|
-
return @uncommitted_changes
|
56
|
-
end
|
57
|
-
alias_method :has_uncommitted_changes?, :uncommitted_changes?
|
58
|
-
|
59
|
-
|
60
74
|
### Return the ID as a String in the form used by the command line.
|
61
75
|
def to_s
|
62
76
|
str = self.global.dup
|
data/lib/hglib/repo/log_entry.rb
CHANGED
@@ -30,18 +30,18 @@ class Hglib::Repo::LogEntry
|
|
30
30
|
|
31
31
|
### Create a new log entry from the raw +entryhash+.
|
32
32
|
def initialize( entryhash )
|
33
|
-
@bookmarks = entryhash[
|
34
|
-
@branch = entryhash[
|
35
|
-
@date = entryhash[
|
36
|
-
@desc = entryhash[
|
37
|
-
@node = entryhash[
|
38
|
-
@parents = entryhash[
|
39
|
-
@phase = entryhash[
|
40
|
-
@rev = entryhash[
|
41
|
-
@tags = entryhash[
|
42
|
-
@user = entryhash[
|
43
|
-
@date = entryhash[
|
44
|
-
@files = entryhash[
|
33
|
+
@bookmarks = entryhash[ :bookmarks ]
|
34
|
+
@branch = entryhash[ :branch ]
|
35
|
+
@date = entryhash[ :date ]
|
36
|
+
@desc = entryhash[ :desc ]
|
37
|
+
@node = entryhash[ :node ]
|
38
|
+
@parents = entryhash[ :parents ]
|
39
|
+
@phase = entryhash[ :phase ]
|
40
|
+
@rev = entryhash[ :rev ]
|
41
|
+
@tags = entryhash[ :tags ]
|
42
|
+
@user = entryhash[ :user ]
|
43
|
+
@date = entryhash[ :date ]
|
44
|
+
@files = entryhash[ :files ] || []
|
45
45
|
end
|
46
46
|
|
47
47
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'loggability'
|
5
|
+
|
6
|
+
require 'hglib/repo' unless defined?( Hglib::Repo )
|
7
|
+
|
8
|
+
|
9
|
+
class Hglib::Repo::Tag
|
10
|
+
extend Loggability
|
11
|
+
|
12
|
+
|
13
|
+
# Send logs to the Hglib logger
|
14
|
+
log_to :hglib
|
15
|
+
|
16
|
+
|
17
|
+
### Create a tag object.
|
18
|
+
def initialize( repo, tag:, node:, rev: 0, type: '' )
|
19
|
+
@repo = repo
|
20
|
+
@name = tag
|
21
|
+
@node = node
|
22
|
+
@rev = rev
|
23
|
+
@type = type
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
######
|
28
|
+
public
|
29
|
+
######
|
30
|
+
|
31
|
+
##
|
32
|
+
# The repo the tag belongs to
|
33
|
+
attr_reader :repo
|
34
|
+
|
35
|
+
##
|
36
|
+
# The tag's name
|
37
|
+
attr_reader :name
|
38
|
+
|
39
|
+
##
|
40
|
+
# The SHA of the node the tag points to
|
41
|
+
attr_reader :node
|
42
|
+
|
43
|
+
##
|
44
|
+
# The numeric revision the tag points to
|
45
|
+
attr_reader :rev
|
46
|
+
|
47
|
+
##
|
48
|
+
# The tag type
|
49
|
+
attr_reader :type
|
50
|
+
|
51
|
+
end # class Hglib::Repo::Tag
|
52
|
+
|
data/lib/hglib/server.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# -*- ruby -*-
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'json'
|
4
5
|
require 'shellwords'
|
5
6
|
require 'loggability'
|
6
7
|
require 'hglib' unless defined?( Hglib )
|
@@ -41,7 +42,7 @@ class Hglib::Server
|
|
41
42
|
[ optname ]
|
42
43
|
when FalseClass, NilClass
|
43
44
|
[ optname.sub(/\A--/, '--no-') ] if optname.start_with?( '--' )
|
44
|
-
when String
|
45
|
+
when String, Numeric
|
45
46
|
if optname.start_with?( '--' )
|
46
47
|
[ "#{optname}=#{val}" ]
|
47
48
|
else
|
@@ -136,15 +137,15 @@ class Hglib::Server
|
|
136
137
|
### #on_byte_input and #on_line_input will be used to read it. If one of these
|
137
138
|
### callbacks is not registered, an IOError will be raised.
|
138
139
|
def run( command, *args, **options )
|
140
|
+
args = args.compact
|
139
141
|
self.log.debug "Running command: %p" % [ Shellwords.join([command.to_s] + args) ]
|
140
142
|
self.start unless self.started?
|
141
143
|
|
142
144
|
done = false
|
143
|
-
output =
|
145
|
+
output = String.new
|
146
|
+
errors = []
|
144
147
|
|
145
|
-
args.compact!
|
146
148
|
args += self.class.mangle_options( options )
|
147
|
-
|
148
149
|
self.write_command( 'runcommand', command, *args )
|
149
150
|
|
150
151
|
until done
|
@@ -158,7 +159,7 @@ class Hglib::Server
|
|
158
159
|
done = true
|
159
160
|
when 'e'
|
160
161
|
self.log.error "Got command error: %p" % [ data ]
|
161
|
-
|
162
|
+
errors << data
|
162
163
|
when 'L'
|
163
164
|
self.log.debug "Server requested line input (%d bytes)" % [ data ]
|
164
165
|
input = self.get_line_input( data.to_i )
|
@@ -174,10 +175,23 @@ class Hglib::Server
|
|
174
175
|
end
|
175
176
|
end
|
176
177
|
|
178
|
+
raise Hglib::CommandError, [command, *errors] unless errors.empty?
|
179
|
+
|
177
180
|
return output
|
178
181
|
end
|
179
182
|
|
180
183
|
|
184
|
+
### Run the specified +command+ with the given +args+ with the JSON template and
|
185
|
+
### return the result.
|
186
|
+
def run_with_json_template( command, *args, symbolize: true, **options )
|
187
|
+
options[:T] = 'json'
|
188
|
+
|
189
|
+
json = self.run( command, *args, **options )
|
190
|
+
|
191
|
+
return JSON.parse( json, symbolize_names: symbolize )
|
192
|
+
end
|
193
|
+
|
194
|
+
|
181
195
|
### Returns +true+ if the underlying command server has been started.
|
182
196
|
def is_started?
|
183
197
|
return self.pid ? true : false
|
@@ -302,8 +316,11 @@ class Hglib::Server
|
|
302
316
|
|
303
317
|
### Return the command-line command for starting the command server.
|
304
318
|
def server_start_command
|
319
|
+
hg = Hglib.hg_path
|
320
|
+
raise "couldn't find an `hg' executable in your PATH!" unless hg.executable?
|
321
|
+
|
305
322
|
cmd = [
|
306
|
-
|
323
|
+
hg.to_s,
|
307
324
|
'--config',
|
308
325
|
'ui.interactive=True',
|
309
326
|
'serve',
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib/config'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Hglib::Config do
|
9
|
+
|
10
|
+
let( :entries ) do
|
11
|
+
return [
|
12
|
+
{:name=>"progress.delay", :source=>"/Users/ged/.hgrc:96", :value=>"0.1"},
|
13
|
+
{:name=>"progress.refresh", :source=>"/Users/ged/.hgrc:97", :value=>"0.1"},
|
14
|
+
{:name=>"progress.format", :source=>"/Users/ged/.hgrc:98", :value=>"topic bar number"},
|
15
|
+
{:name=>"progress.clear-complete", :source=>"/Users/ged/.hgrc:99", :value=>"True"},
|
16
|
+
{:name=>"server.bundle1", :source=>"", :value=>"False"},
|
17
|
+
{:name=>"ui.editor", :source=>"$VISUAL", :value=>"emacs"},
|
18
|
+
{:name=>"ui.ssh", :source=>"/Users/ged/.hgrc:3", :value=>"ssh -C"},
|
19
|
+
{:name=>"ui.ignore", :source=>"/Users/ged/.hgrc:4", :value=>"~/.hgignore_global"},
|
20
|
+
{:name=>"ui.merge", :source=>"/Users/ged/.hgrc:5", :value=>"Kaleidoscope"},
|
21
|
+
{:name=>"ui.interactive", :source=>"--config", :value=>"True"},
|
22
|
+
{:name=>"ui.nontty", :source=>"commandserver", :value=>"true"},
|
23
|
+
{:name=>"web.cacerts", :source=>"/Users/ged/.hgrc:122", :value=>""},
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
it "expands config items" do
|
29
|
+
instance = described_class.new( entries )
|
30
|
+
|
31
|
+
expect( instance['ui.editor'] ).to eq( 'emacs' )
|
32
|
+
expect( instance['progress.refresh'] ).to eq( '0.1' )
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib/mixins'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Hglib, "mixins" do
|
9
|
+
|
10
|
+
describe Hglib::MethodUtilities, 'used to extend a class' do
|
11
|
+
|
12
|
+
let( :extended_class ) do
|
13
|
+
klass = Class.new
|
14
|
+
klass.extend( Hglib::MethodUtilities )
|
15
|
+
klass
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
it "can declare a class-level attribute reader" do
|
20
|
+
extended_class.singleton_attr_reader :foo
|
21
|
+
expect( extended_class ).to respond_to( :foo )
|
22
|
+
expect( extended_class ).to_not respond_to( :foo= )
|
23
|
+
expect( extended_class ).to_not respond_to( :foo? )
|
24
|
+
end
|
25
|
+
|
26
|
+
it "can declare a class-level attribute writer" do
|
27
|
+
extended_class.singleton_attr_writer :foo
|
28
|
+
expect( extended_class ).to_not respond_to( :foo )
|
29
|
+
expect( extended_class ).to respond_to( :foo= )
|
30
|
+
expect( extended_class ).to_not respond_to( :foo? )
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can declare a class-level attribute reader and writer" do
|
34
|
+
extended_class.singleton_attr_accessor :foo
|
35
|
+
expect( extended_class ).to respond_to( :foo )
|
36
|
+
expect( extended_class ).to respond_to( :foo= )
|
37
|
+
expect( extended_class ).to_not respond_to( :foo? )
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can declare a class-level alias" do
|
41
|
+
def extended_class.foo
|
42
|
+
return "foo"
|
43
|
+
end
|
44
|
+
extended_class.singleton_method_alias( :bar, :foo )
|
45
|
+
|
46
|
+
expect( extended_class.bar ).to eq( 'foo' )
|
47
|
+
end
|
48
|
+
|
49
|
+
it "can declare an instance attribute predicate method" do
|
50
|
+
extended_class.attr_predicate :foo
|
51
|
+
instance = extended_class.new
|
52
|
+
|
53
|
+
expect( instance ).to_not respond_to( :foo )
|
54
|
+
expect( instance ).to_not respond_to( :foo= )
|
55
|
+
expect( instance ).to respond_to( :foo? )
|
56
|
+
|
57
|
+
expect( instance.foo? ).to eq( false )
|
58
|
+
|
59
|
+
instance.instance_variable_set( :@foo, 1 )
|
60
|
+
expect( instance.foo? ).to eq( true )
|
61
|
+
end
|
62
|
+
|
63
|
+
it "can declare an instance attribute predicate and writer" do
|
64
|
+
extended_class.attr_predicate_accessor :foo
|
65
|
+
instance = extended_class.new
|
66
|
+
|
67
|
+
expect( instance ).to_not respond_to( :foo )
|
68
|
+
expect( instance ).to respond_to( :foo= )
|
69
|
+
expect( instance ).to respond_to( :foo? )
|
70
|
+
|
71
|
+
expect( instance.foo? ).to eq( false )
|
72
|
+
|
73
|
+
instance.foo = 1
|
74
|
+
expect( instance.foo? ).to eq( true )
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|