hglib 0.2.0 → 0.3.0
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.
- 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
|
+
|