hglib 0.4.0 → 0.5.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 +10 -0
- data/lib/hglib.rb +51 -36
- data/lib/hglib/extension.rb +50 -0
- data/lib/hglib/extension/gpg.rb +36 -0
- data/lib/hglib/mixins.rb +4 -1
- data/lib/hglib/repo.rb +11 -44
- data/lib/hglib/repo/status_entry.rb +77 -0
- data/lib/hglib/server.rb +27 -3
- data/lib/hglib/version_info.rb +40 -0
- data/spec/hglib/extension/gpg_spec.rb +33 -0
- data/spec/hglib/extension_spec.rb +18 -0
- data/spec/hglib/repo/status_entry_spec.rb +42 -0
- data/spec/hglib/version_info_spec.rb +88 -0
- data/spec/hglib_spec.rb +22 -76
- metadata +16 -8
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c3e4ce0e0a5a9fae8575225359cc5b8e922cfd009b1ceade3a3ed4f4a9865a9
|
4
|
+
data.tar.gz: 5d1e25766012a16829958a194398394eed379555369e36e8c1617641e9ad6da8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f61ab1c13cea52539d27ed42837e58c0be53e4472881c8e5d4e08d9db43bdbf71fbaed4b2fc6b52ea75e14bcdf135121e430449d2953f9ce5c9ad3ee77201d8
|
7
|
+
data.tar.gz: 86e692ee3e36cc058266f644bb84ea2cceeacc2d2f19c6a5898719b67786ffda938843622dbdc28e232d09c4f50ac5785ac8fbe2ddf372a7c0b5b1e679ca0fa1
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/History.md
CHANGED
@@ -2,6 +2,16 @@
|
|
2
2
|
|
3
3
|
---
|
4
4
|
|
5
|
+
## v0.5.0 [2019-10-14] Michael Granger <ged@FaerieMUD.org>
|
6
|
+
|
7
|
+
Improvements:
|
8
|
+
|
9
|
+
- Add a mechanism for defining methods that support Mercurial extensions
|
10
|
+
- Move the version methods into a mixin and expose them on both Hglib and
|
11
|
+
Hglib::Repo instances.
|
12
|
+
- Add an extension for gpg
|
13
|
+
|
14
|
+
|
5
15
|
## v0.4.0 [2019-10-12] Michael Granger <ged@FaerieMUD.org>
|
6
16
|
|
7
17
|
Changes:
|
data/lib/hglib.rb
CHANGED
@@ -12,7 +12,7 @@ module Hglib
|
|
12
12
|
Exception2MessageMapper
|
13
13
|
|
14
14
|
# Package version
|
15
|
-
VERSION = '0.
|
15
|
+
VERSION = '0.5.0'
|
16
16
|
|
17
17
|
# Version control revision
|
18
18
|
REVISION = %q$Revision$
|
@@ -30,15 +30,18 @@ module Hglib
|
|
30
30
|
# Base exception class for errors raised by this library
|
31
31
|
def_exception :Error, "hglib error"
|
32
32
|
|
33
|
-
|
33
|
+
# Specialized exception for handling errors returned by the command server.
|
34
34
|
class CommandError < Hglib::Error
|
35
35
|
|
36
|
-
|
37
|
-
|
38
|
-
@
|
36
|
+
### Create a new CommandError with the given +args+.
|
37
|
+
def initialize( command, *messages, details: nil )
|
38
|
+
@command = command
|
39
|
+
@messages = messages.flatten.map( &:chomp )
|
39
40
|
@messages << "error in hg command" if @messages.empty?
|
41
|
+
@details = details
|
40
42
|
end
|
41
43
|
|
44
|
+
|
42
45
|
##
|
43
46
|
# The command that resulted in an error
|
44
47
|
attr_reader :command
|
@@ -47,6 +50,10 @@ module Hglib
|
|
47
50
|
# The Array of error messages generated by the command
|
48
51
|
attr_reader :messages
|
49
52
|
|
53
|
+
##
|
54
|
+
# Additional details of the error
|
55
|
+
attr_reader :details
|
56
|
+
|
50
57
|
|
51
58
|
### Returns +true+ if the command resulted in more than one error message.
|
52
59
|
def multiple?
|
@@ -54,7 +61,7 @@ module Hglib
|
|
54
61
|
end
|
55
62
|
|
56
63
|
|
57
|
-
### Overridden to
|
64
|
+
### Overridden to format multi-message errors in a more-readable way.
|
58
65
|
def message
|
59
66
|
msg = String.new( encoding: 'utf-8' )
|
60
67
|
|
@@ -69,12 +76,46 @@ module Hglib
|
|
69
76
|
msg << ' ' << self.messages.first
|
70
77
|
end
|
71
78
|
|
79
|
+
msg << "\n" << self.details if self.details
|
80
|
+
|
72
81
|
return msg
|
73
82
|
end
|
74
83
|
|
75
84
|
end # class CommandError
|
76
85
|
|
77
86
|
|
87
|
+
# Exception raised when a command failed because the extension it belongs to was
|
88
|
+
# disabled.
|
89
|
+
class DisabledExtensionError < Hglib::Error
|
90
|
+
|
91
|
+
### Create a new instance for the given +command+ and the name of the
|
92
|
+
### +extension+ which defines it.
|
93
|
+
def initialize( command, extension )
|
94
|
+
@command = command
|
95
|
+
@extension = extension
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
##
|
100
|
+
# The command that failed
|
101
|
+
attr_reader :command
|
102
|
+
|
103
|
+
##
|
104
|
+
# The name of the extension which defines the #command
|
105
|
+
attr_reader :extension
|
106
|
+
|
107
|
+
|
108
|
+
### Return an message describing what the command and disabled extension were.
|
109
|
+
def message
|
110
|
+
return "`%s`: command is provided by disabled extension `%s`" % [
|
111
|
+
self.command,
|
112
|
+
self.extension,
|
113
|
+
]
|
114
|
+
end
|
115
|
+
|
116
|
+
end # class DisabledError
|
117
|
+
|
118
|
+
|
78
119
|
# Loggability API -- set up a Logger for Hglib objects
|
79
120
|
log_as :hglib
|
80
121
|
|
@@ -95,6 +136,8 @@ module Hglib
|
|
95
136
|
autoload :Config, 'hglib/config'
|
96
137
|
autoload :Server, 'hglib/server'
|
97
138
|
autoload :Repo, 'hglib/repo'
|
139
|
+
autoload :Extension, 'hglib/extension'
|
140
|
+
autoload :VersionInfo, 'hglib/version_info'
|
98
141
|
|
99
142
|
|
100
143
|
### Return an Hglib::Server started with no repository.
|
@@ -149,36 +192,8 @@ module Hglib
|
|
149
192
|
end
|
150
193
|
|
151
194
|
|
152
|
-
|
153
|
-
|
154
|
-
response = self.server.run_with_json_template( :version )
|
155
|
-
self.logger.debug "Got a VERSION response: %p" % [ response ]
|
156
|
-
|
157
|
-
return response.first
|
158
|
-
end
|
159
|
-
|
160
|
-
|
161
|
-
### Fetch the version of Mercurial that's being used as a String.
|
162
|
-
def self::version
|
163
|
-
return self.versions[ :ver ]
|
164
|
-
end
|
165
|
-
|
166
|
-
|
167
|
-
### Fetch the version of the Mercurial extensions that're being used as a Hash.
|
168
|
-
def self::extension_versions
|
169
|
-
ext_info = self.versions[ :extensions ]
|
170
|
-
return ext_info.each_with_object({}) do |ext, hash|
|
171
|
-
ext = ext.dup
|
172
|
-
hash[ ext.delete(:name).to_sym ] = ext
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
|
177
|
-
### Returns +true+ if the extension with the given +name+ is enabled in the
|
178
|
-
### current (global) configuration.
|
179
|
-
def self::extension_enabled?( name )
|
180
|
-
return self.extension_versions.key?( name.to_sym )
|
181
|
-
end
|
195
|
+
extend Hglib::VersionInfo
|
196
|
+
Hglib::Extension.load_all
|
182
197
|
|
183
198
|
end # module Hglib
|
184
199
|
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
require 'loggability'
|
6
|
+
|
7
|
+
require 'hglib' unless defined?( Hglib )
|
8
|
+
|
9
|
+
|
10
|
+
module Hglib::Extension
|
11
|
+
extend Loggability
|
12
|
+
|
13
|
+
# Loggability API -- log to the Hglib logger
|
14
|
+
log_to :hglib
|
15
|
+
|
16
|
+
|
17
|
+
### Load all of the extensions.
|
18
|
+
def self::load_all
|
19
|
+
# :TODO: Allow gem extensions?
|
20
|
+
extdir = Pathname( __FILE__ ).dirname + 'extension'
|
21
|
+
Pathname.glob( extdir + '*.rb' ).each do |extpath|
|
22
|
+
self.log.debug "Loading extensions from %s" % [ extpath ]
|
23
|
+
require( extpath )
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
### Define one or more commands that should be attached to Repo objects.
|
29
|
+
def repo_commands( &block )
|
30
|
+
raise LocalJumpError, "no block given" unless block
|
31
|
+
|
32
|
+
mod = Module.new
|
33
|
+
mod.class_eval( &block )
|
34
|
+
|
35
|
+
Hglib::Repo.include( mod )
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
### Define one or more commands that should be attached to the Hglib module.
|
40
|
+
def global_commands( &block )
|
41
|
+
raise LocalJumpError, "no block given" unless block
|
42
|
+
|
43
|
+
mod = Module.new
|
44
|
+
mod.class_eval( &block )
|
45
|
+
|
46
|
+
Hglib.extend( mod )
|
47
|
+
end
|
48
|
+
|
49
|
+
end # module Hglib::Extension
|
50
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'hglib/extension' unless defined?( Hglib::Extension )
|
5
|
+
|
6
|
+
|
7
|
+
module Hglib::Extension::GPG
|
8
|
+
extend Hglib::Extension
|
9
|
+
|
10
|
+
|
11
|
+
repo_commands do
|
12
|
+
|
13
|
+
### Sign the given +rev+ (or the current one if not specified).
|
14
|
+
def sign( rev=nil, **options )
|
15
|
+
response = self.server.run( :sign, rev, **options )
|
16
|
+
return response.chomp
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
### Check the signature of the given +rev+.
|
21
|
+
def sigcheck( rev, **options )
|
22
|
+
response = self.server.run( :sigcheck, rev, **options )
|
23
|
+
return response.chomp
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
### Return an Array describing all of the signed changesets.
|
28
|
+
def sigs( **options )
|
29
|
+
response = self.server.run( :sigs, **options )
|
30
|
+
return response.lines.map( &:chomp )
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end # module Hglib::Extension::GPG
|
36
|
+
|
data/lib/hglib/mixins.rb
CHANGED
@@ -57,7 +57,10 @@ module Hglib
|
|
57
57
|
def attr_predicate( attrname )
|
58
58
|
attrname = attrname.to_s.chomp( '?' )
|
59
59
|
define_method( "#{attrname}?" ) do
|
60
|
-
|
60
|
+
ivar = "@#{attrname}"
|
61
|
+
instance_variable_defined?( ivar ) && instance_variable_get( ivar ) ?
|
62
|
+
true :
|
63
|
+
false
|
61
64
|
end
|
62
65
|
end
|
63
66
|
|
data/lib/hglib/repo.rb
CHANGED
@@ -3,11 +3,14 @@
|
|
3
3
|
|
4
4
|
require 'json'
|
5
5
|
require 'loggability'
|
6
|
+
|
6
7
|
require 'hglib' unless defined?( Hglib )
|
8
|
+
require 'hglib/version_info'
|
7
9
|
|
8
10
|
|
9
11
|
class Hglib::Repo
|
10
12
|
extend Loggability
|
13
|
+
include Hglib::VersionInfo
|
11
14
|
|
12
15
|
# Loggability API -- log to the hglib logger
|
13
16
|
log_to :hglib
|
@@ -48,7 +51,6 @@ class Hglib::Repo
|
|
48
51
|
### requested statuses.
|
49
52
|
def status( *args, **options )
|
50
53
|
response = self.server.run_with_json_template( :status, *args, **options )
|
51
|
-
self.logger.debug "Parsing status response: %p" % [ response ]
|
52
54
|
|
53
55
|
return response.map {|entry| Hglib::Repo::StatusEntry.new(entry) }
|
54
56
|
end
|
@@ -60,7 +62,6 @@ class Hglib::Repo
|
|
60
62
|
### of `.` identifies the working directory parent without uncommitted changes.
|
61
63
|
def identify( source=nil, **options )
|
62
64
|
response = self.server.run_with_json_template( :identify, source, **options )
|
63
|
-
self.logger.debug "Got ID response: %p" % [ response ]
|
64
65
|
|
65
66
|
data = response.first
|
66
67
|
return Hglib::Repo::Id.new( **data )
|
@@ -75,7 +76,6 @@ class Hglib::Repo
|
|
75
76
|
options[:graph] = false
|
76
77
|
|
77
78
|
entries = self.server.run_with_json_template( :log, *files, **options )
|
78
|
-
self.logger.debug "Got log response: %p" % [ entries ]
|
79
79
|
|
80
80
|
return entries.map {|entry| Hglib::Repo::LogEntry.new(entry) }
|
81
81
|
end
|
@@ -84,9 +84,7 @@ class Hglib::Repo
|
|
84
84
|
### Return a String showing differences between revisions for the specified
|
85
85
|
### +files+ in the unified diff format.
|
86
86
|
def diff( *files, **options )
|
87
|
-
|
88
|
-
self.logger.debug "Got diff response: %p" % [ truncate(response) ]
|
89
|
-
return response
|
87
|
+
return self.server.run( :diff, *files, **options )
|
90
88
|
end
|
91
89
|
|
92
90
|
|
@@ -98,9 +96,7 @@ class Hglib::Repo
|
|
98
96
|
###
|
99
97
|
### Returns <code>true</code> if all files are successfully added.
|
100
98
|
def add( *files, **options )
|
101
|
-
|
102
|
-
self.logger.debug "Got ADD response: %p" % [ response ]
|
103
|
-
|
99
|
+
self.server.run( :add, *files, **options )
|
104
100
|
return true
|
105
101
|
end
|
106
102
|
|
@@ -122,9 +118,7 @@ class Hglib::Repo
|
|
122
118
|
###
|
123
119
|
### Returns <code>true</code> if all files are successfully added.
|
124
120
|
def addremove( *files, **options )
|
125
|
-
|
126
|
-
self.logger.debug "Got ADD response: %p" % [ response ]
|
127
|
-
|
121
|
+
self.server.run( :addremove, *files, **options )
|
128
122
|
return true
|
129
123
|
end
|
130
124
|
alias_method :add_remove, :addremove
|
@@ -133,9 +127,7 @@ class Hglib::Repo
|
|
133
127
|
|
134
128
|
### Commit the specified +files+ with the given +options+.
|
135
129
|
def commit( *files, **options )
|
136
|
-
|
137
|
-
self.logger.debug "Got COMMIT response: %p" % [ response ]
|
138
|
-
|
130
|
+
self.server.run( :commit, *files, **options )
|
139
131
|
return true
|
140
132
|
end
|
141
133
|
|
@@ -143,9 +135,7 @@ class Hglib::Repo
|
|
143
135
|
### Pull changes from the specified +source+ (which defaults to the +default+
|
144
136
|
### path) into the local repository.
|
145
137
|
def pull( source=nil, **options )
|
146
|
-
|
147
|
-
self.logger.debug "Got PULL response: %p" % [ response ]
|
148
|
-
|
138
|
+
self.server.run( :pull, source, **options )
|
149
139
|
return true
|
150
140
|
end
|
151
141
|
|
@@ -160,18 +150,14 @@ class Hglib::Repo
|
|
160
150
|
|
161
151
|
### Update the working directory or switch revisions.
|
162
152
|
def update( rev=nil, **options )
|
163
|
-
|
164
|
-
self.logger.debug "Got UPDATE response: %p" % [ response ]
|
165
|
-
|
153
|
+
self.server.run( :update, rev, **options )
|
166
154
|
return true
|
167
155
|
end
|
168
156
|
|
169
157
|
|
170
158
|
### Push changes to the specified +destination+.
|
171
159
|
def push( destination=nil, **options )
|
172
|
-
|
173
|
-
self.logger.debug "Got PUSH response: %p" % [ response ]
|
174
|
-
|
160
|
+
self.server.run( :push, destination, **options )
|
175
161
|
return true
|
176
162
|
end
|
177
163
|
|
@@ -190,8 +176,6 @@ class Hglib::Repo
|
|
190
176
|
### Return a Hglib::Repo::Tag object for each tag in the repo.
|
191
177
|
def tags
|
192
178
|
response = self.server.run_with_json_template( :tags )
|
193
|
-
self.logger.debug "Got a TAGS response: %p" % [ response ]
|
194
|
-
|
195
179
|
return response.flatten.map {|tag| Hglib::Repo::Tag.new(self, **tag) }
|
196
180
|
end
|
197
181
|
|
@@ -200,9 +184,7 @@ class Hglib::Repo
|
|
200
184
|
def bookmark( *names, **options )
|
201
185
|
raise "expected at least one bookmark name" if names.empty?
|
202
186
|
|
203
|
-
|
204
|
-
self.logger.debug "Got BOOKMARK response: %p" % [ response ]
|
205
|
-
|
187
|
+
self.server.run( :bookmark, *names, **options )
|
206
188
|
return true
|
207
189
|
end
|
208
190
|
|
@@ -211,8 +193,6 @@ class Hglib::Repo
|
|
211
193
|
def bookmarks
|
212
194
|
options = { list: true }
|
213
195
|
response = self.server.run_with_json_template( :bookmarks, **options )
|
214
|
-
self.logger.debug "Got a BOOKMARKS response: %p" % [ response ]
|
215
|
-
|
216
196
|
return response.map {|bk| Hglib::Repo::Bookmark.new(self, **bk) }
|
217
197
|
end
|
218
198
|
|
@@ -221,7 +201,6 @@ class Hglib::Repo
|
|
221
201
|
### object.
|
222
202
|
def config( untrusted: false )
|
223
203
|
options = { untrusted: untrusted }
|
224
|
-
|
225
204
|
config = self.server.run_with_json_template( :showconfig, **options )
|
226
205
|
return Hglib::Config.new( config )
|
227
206
|
end
|
@@ -230,23 +209,12 @@ class Hglib::Repo
|
|
230
209
|
### Fetch a Hash of aliases for remote repositories.
|
231
210
|
def paths
|
232
211
|
response = self.server.run_with_json_template( :paths )
|
233
|
-
self.logger.debug "Got a PATHS response: %p" % [ response ]
|
234
|
-
|
235
212
|
return response.each_with_object({}) do |entry, hash|
|
236
213
|
hash[ entry[:name].to_sym ] = URI( entry[:url] )
|
237
214
|
end
|
238
215
|
end
|
239
216
|
|
240
217
|
|
241
|
-
### Sign the given +rev+ (or the current one if not specified).
|
242
|
-
def sign( rev=nil, **options )
|
243
|
-
response = self.server.run( :sign, rev, **options )
|
244
|
-
self.logger.debug "Got a SIGN response: %p" % [ response ]
|
245
|
-
|
246
|
-
return response.chomp
|
247
|
-
end
|
248
|
-
|
249
|
-
|
250
218
|
### Set or show the current phase name for a +revset+.
|
251
219
|
###
|
252
220
|
### With no +revset+, operates on the current changeset.
|
@@ -263,7 +231,6 @@ class Hglib::Repo
|
|
263
231
|
### setting the phase.
|
264
232
|
def phase( revset=nil, **options )
|
265
233
|
response = self.server.run( :phase, revset, **options )
|
266
|
-
self.logger.debug "Got a PHASE response: %p" % [ response ]
|
267
234
|
|
268
235
|
return {} if response.empty?
|
269
236
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
require 'hglib/repo' unless defined?( Hglib::Repo )
|
7
|
+
|
8
|
+
|
9
|
+
# An entry in a repository's status list.
|
10
|
+
class Hglib::Repo::StatusEntry
|
11
|
+
extend Loggability
|
12
|
+
|
13
|
+
|
14
|
+
# Loggability API -- output to the hglib logger
|
15
|
+
log_to :hglib
|
16
|
+
|
17
|
+
|
18
|
+
# {
|
19
|
+
# :path=>"Rakefile",
|
20
|
+
# :status=>"M"
|
21
|
+
# }
|
22
|
+
|
23
|
+
### Create a new log entry from the raw +entryhash+.
|
24
|
+
def initialize( entryhash )
|
25
|
+
@path = Pathname( entryhash[:path] )
|
26
|
+
@source = Pathname( entryhash[:source] ) if entryhash.key?( :source )
|
27
|
+
@status = entryhash[ :status ]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
######
|
32
|
+
public
|
33
|
+
######
|
34
|
+
|
35
|
+
##
|
36
|
+
# Return the Pathname of the file the status applies to
|
37
|
+
attr_reader :path
|
38
|
+
|
39
|
+
##
|
40
|
+
# The Pathname of the file the status applies to was copied from (if the status
|
41
|
+
# is `A`/`added`) and the addition was via a copy/move operation.
|
42
|
+
attr_reader :source
|
43
|
+
|
44
|
+
##
|
45
|
+
# Return the character that denotes the file's status
|
46
|
+
attr_reader :status
|
47
|
+
|
48
|
+
|
49
|
+
### Return the human-readable status.
|
50
|
+
def status_description
|
51
|
+
return case self.status
|
52
|
+
when 'M' then 'modified'
|
53
|
+
when 'A' then 'added'
|
54
|
+
when 'R' then 'removed'
|
55
|
+
when 'C' then 'clean'
|
56
|
+
when '!' then 'missing'
|
57
|
+
when '?' then 'not tracked'
|
58
|
+
when 'I' then 'ignored'
|
59
|
+
else
|
60
|
+
raise "unknown status %p" % [ self.status ]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
### Return a human-readable representation of the StatusEntry as a String.
|
66
|
+
def inspect
|
67
|
+
return "#<%p:#%x %s: %s%s>" % [
|
68
|
+
self.class,
|
69
|
+
self.object_id * 2,
|
70
|
+
self.path,
|
71
|
+
self.status_description,
|
72
|
+
self.source ? " via copy/move from #{self.source}" : '',
|
73
|
+
]
|
74
|
+
end
|
75
|
+
|
76
|
+
end # class Hglib::Repo::StatusEntry
|
77
|
+
|
data/lib/hglib/server.rb
CHANGED
@@ -26,6 +26,14 @@ class Hglib::Server
|
|
26
26
|
# Array#pack template for plain messages sent to the command server
|
27
27
|
MESSAGE_TEMPLATE = 'I>A*'
|
28
28
|
|
29
|
+
# A Regexp to match the detail message when a command belongs to a disabled
|
30
|
+
# extension.
|
31
|
+
EXTENSION_DISABLED_DETAILS = %r{
|
32
|
+
(?-x:is provided by the following extension:)
|
33
|
+
\s+
|
34
|
+
(?<extension_name>\w+)
|
35
|
+
}x
|
36
|
+
|
29
37
|
|
30
38
|
# Loggability API -- send logs to the logger in the top-level module
|
31
39
|
log_to :hglib
|
@@ -147,7 +155,7 @@ class Hglib::Server
|
|
147
155
|
### callbacks is not registered, an IOError will be raised.
|
148
156
|
def run( command, *args, **options )
|
149
157
|
args = args.compact
|
150
|
-
self.log.debug "Running command: %p" % [ Shellwords.join([command.to_s] + args) ]
|
158
|
+
self.log.debug { "Running command: %p" % [ Shellwords.join([command.to_s] + args) ] }
|
151
159
|
self.start unless self.started?
|
152
160
|
|
153
161
|
done = false
|
@@ -184,12 +192,28 @@ class Hglib::Server
|
|
184
192
|
end
|
185
193
|
end
|
186
194
|
|
187
|
-
|
195
|
+
self.handle_errors( command, errors, output ) unless errors.empty?
|
188
196
|
|
197
|
+
self.log.debug { "Got %s response: %p" % [ command.to_s.upcase, output ] }
|
189
198
|
return output
|
190
199
|
end
|
191
200
|
|
192
201
|
|
202
|
+
### Form and raise an exception for the given +errors+ resulting from running
|
203
|
+
### +command+.
|
204
|
+
def handle_errors( command, errors, details )
|
205
|
+
err = nil
|
206
|
+
|
207
|
+
if details && (m = details.match(EXTENSION_DISABLED_DETAILS) )
|
208
|
+
err = Hglib::DisabledExtensionError.new( command, m[:extension_name] )
|
209
|
+
else
|
210
|
+
err = Hglib::CommandError.new( command, errors, details: details )
|
211
|
+
end
|
212
|
+
|
213
|
+
raise( err, nil, caller(2) )
|
214
|
+
end
|
215
|
+
|
216
|
+
|
193
217
|
### Run the specified +command+ with the given +args+ with the JSON template and
|
194
218
|
### return the result.
|
195
219
|
def run_with_json_template( command, *args, symbolize: true, **options )
|
@@ -318,7 +342,7 @@ class Hglib::Server
|
|
318
342
|
|
319
343
|
self.log.debug "Reading %d more bytes of the message" % [ bytes ]
|
320
344
|
message = self.reader.read( bytes ) unless bytes.zero?
|
321
|
-
self.log.debug " read message: %p" % [ message ]
|
345
|
+
self.log.debug { " read message: %p" % [ message ] }
|
322
346
|
return channel, message
|
323
347
|
end
|
324
348
|
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'hglib' unless defined?( Hglib )
|
5
|
+
|
6
|
+
|
7
|
+
# Version information methods for Repos and the top-level module.
|
8
|
+
module Hglib::VersionInfo
|
9
|
+
|
10
|
+
### Fetch a Hash of version information about the Mercurial that is being used.
|
11
|
+
def versions
|
12
|
+
response = self.server.run_with_json_template( :version )
|
13
|
+
return response.first
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
### Fetch the version of Mercurial that's being used as a String.
|
18
|
+
def version
|
19
|
+
return self.versions[ :ver ]
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
### Fetch the version of the Mercurial extensions that're being used as a Hash.
|
24
|
+
def extension_versions
|
25
|
+
ext_info = self.versions[ :extensions ]
|
26
|
+
return ext_info.each_with_object({}) do |ext, hash|
|
27
|
+
ext = ext.dup
|
28
|
+
hash[ ext.delete(:name).to_sym ] = ext
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
### Returns +true+ if the extension with the given +name+ is enabled in the
|
34
|
+
### current (global) configuration.
|
35
|
+
def extension_enabled?( name )
|
36
|
+
return self.extension_versions.key?( name.to_sym )
|
37
|
+
end
|
38
|
+
|
39
|
+
end # module Hglib::VersionInfo
|
40
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib/extension/gpg'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Hglib::Extension::GPG do
|
9
|
+
|
10
|
+
let( :repo_dir ) do
|
11
|
+
Dir.mktmpdir( ['hglib', 'repodir'] )
|
12
|
+
end
|
13
|
+
|
14
|
+
let( :server ) { instance_double(Hglib::Server) }
|
15
|
+
|
16
|
+
let( :repo ) { Hglib::Repo.new( repo_dir ) }
|
17
|
+
|
18
|
+
before( :each ) do
|
19
|
+
allow( Hglib::Server ).to receive( :new ).and_return( server )
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
it "can sign a revision" do
|
25
|
+
expect( server ).to receive( :run ).
|
26
|
+
with( :sign, nil, {} ).
|
27
|
+
and_return( "signing 2:2b937981802a\n" )
|
28
|
+
|
29
|
+
expect( repo.sign ).to eq( "signing 2:2b937981802a" )
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib'
|
6
|
+
require 'hglib/extension'
|
7
|
+
require 'hglib/repo'
|
8
|
+
|
9
|
+
|
10
|
+
RSpec.describe Hglib::Extension do
|
11
|
+
|
12
|
+
it "adds methods to support Mercurial extensions when loaded" do
|
13
|
+
described_class.load_all
|
14
|
+
expect( Hglib::Repo.instance_methods ).to include( :sign )
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby -S rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../../spec_helper'
|
4
|
+
|
5
|
+
require 'hglib/repo/status_entry'
|
6
|
+
|
7
|
+
|
8
|
+
RSpec.describe Hglib::Repo::StatusEntry do
|
9
|
+
|
10
|
+
RAW_STATUS_ENTRY = {
|
11
|
+
path: 'Rakefile',
|
12
|
+
status: 'M',
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
RAW_COPY_STATUS_ENTRY = {
|
16
|
+
path: "AnotherRakefile",
|
17
|
+
source: "Rakefile",
|
18
|
+
status: "A"
|
19
|
+
}
|
20
|
+
|
21
|
+
it "can be created from the JSON status hash" do
|
22
|
+
entry = described_class.new( RAW_STATUS_ENTRY )
|
23
|
+
|
24
|
+
expect( entry ).to be_a( described_class )
|
25
|
+
expect( entry.path ).to eq( Pathname('Rakefile') )
|
26
|
+
expect( entry.status ).to eq( 'M' )
|
27
|
+
expect( entry.status_description ).to eq( 'modified' )
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
it "can be created from the JSON status hash run with --copies enabled" do
|
32
|
+
entry = described_class.new( RAW_COPY_STATUS_ENTRY )
|
33
|
+
|
34
|
+
expect( entry ).to be_a( described_class )
|
35
|
+
expect( entry.path ).to eq( Pathname('AnotherRakefile') )
|
36
|
+
expect( entry.status ).to eq( 'A' )
|
37
|
+
expect( entry.source ).to eq( Pathname('Rakefile') )
|
38
|
+
expect( entry.status_description ).to eq( 'added' )
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd
|
2
|
+
|
3
|
+
require_relative '../spec_helper'
|
4
|
+
|
5
|
+
require 'loggability'
|
6
|
+
require 'hglib/version_info'
|
7
|
+
|
8
|
+
|
9
|
+
RSpec.describe Hglib::VersionInfo do
|
10
|
+
|
11
|
+
let( :version_info ) {[{
|
12
|
+
extensions: [
|
13
|
+
{bundled: true, name: "churn", ver: nil},
|
14
|
+
{bundled: true, name: "convert", ver: nil},
|
15
|
+
{bundled: false, name: "evolve", ver: "9.2.0"},
|
16
|
+
{bundled: true, name: "extdiff", ver: nil},
|
17
|
+
{bundled: true, name: "gpg", ver: nil},
|
18
|
+
{bundled: false, name: "hggit", ver: "0.8.12 (dulwich 0.19.10)"},
|
19
|
+
{bundled: true, name: "strip", ver: nil},
|
20
|
+
{bundled: true, name: "mq", ver: nil},
|
21
|
+
{bundled: false, name: "prompt", ver: nil},
|
22
|
+
{bundled: true, name: "purge", ver: nil},
|
23
|
+
{bundled: true, name: "rebase", ver: nil},
|
24
|
+
{bundled: false, name: "topic", ver: "0.17.0"},
|
25
|
+
{bundled: true, name: "histedit", ver: nil}
|
26
|
+
],
|
27
|
+
ver: "5.1.1"
|
28
|
+
}]}
|
29
|
+
|
30
|
+
let( :including_class ) do
|
31
|
+
cls = Class.new do
|
32
|
+
extend Loggability
|
33
|
+
log_to :hglib
|
34
|
+
def initialize( server )
|
35
|
+
@server = server
|
36
|
+
end
|
37
|
+
attr_reader :server
|
38
|
+
end
|
39
|
+
cls.include( described_class )
|
40
|
+
cls
|
41
|
+
end
|
42
|
+
|
43
|
+
let( :server ) { instance_double(Hglib::Server, stop: nil) }
|
44
|
+
|
45
|
+
let( :extended_object ) { including_class.new(server) }
|
46
|
+
|
47
|
+
before( :each ) do
|
48
|
+
expect( server ).to receive( :run_with_json_template ).
|
49
|
+
with( :version ).
|
50
|
+
and_return( version_info ).
|
51
|
+
at_least( :once )
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
it "can fetch the versions of Mercurial and loaded extensions" do
|
56
|
+
result = extended_object.versions
|
57
|
+
|
58
|
+
expect( result ).to eq( version_info.first )
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
it "can fetch the simple version of Mercurial" do
|
63
|
+
result = extended_object.version
|
64
|
+
|
65
|
+
expect( result ).to eq( version_info.first[:ver] )
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
it "can fetch the versions of all loaded Mercurial extensions" do
|
70
|
+
result = extended_object.extension_versions
|
71
|
+
|
72
|
+
expect( result ).to be_a( Hash )
|
73
|
+
expect( result ).to include(
|
74
|
+
churn: {bundled: true, ver: nil},
|
75
|
+
evolve: {bundled: false, ver: '9.2.0'},
|
76
|
+
topic: {bundled: false, ver: '0.17.0'},
|
77
|
+
hggit: {bundled: false, ver: "0.8.12 (dulwich 0.19.10)"}
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
it "knows if a given extension is enabled" do
|
83
|
+
expect( extended_object.extension_enabled?('topic') ).to be_truthy
|
84
|
+
expect( extended_object.extension_enabled?('keyword') ).to be_falsey
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
data/spec/hglib_spec.rb
CHANGED
@@ -86,9 +86,10 @@ RSpec.describe Hglib do
|
|
86
86
|
|
87
87
|
|
88
88
|
it "can be created with a single error message" do
|
89
|
-
exception = rescued
|
90
|
-
|
91
|
-
|
89
|
+
exception = rescued do
|
90
|
+
exc = Hglib::CommandError.new( :status, "no_status: No such file or directory\n" )
|
91
|
+
raise( exc, nil, caller(2) )
|
92
|
+
end
|
92
93
|
|
93
94
|
expect( exception ).to_not be_multiple
|
94
95
|
expect( exception.message ).to eq( "`status`: no_status: No such file or directory" )
|
@@ -96,13 +97,14 @@ RSpec.describe Hglib do
|
|
96
97
|
|
97
98
|
|
98
99
|
it "can be created with multiple error messages" do
|
99
|
-
exception = rescued
|
100
|
-
|
100
|
+
exception = rescued do
|
101
|
+
exc = Hglib::CommandError.new(
|
101
102
|
:status,
|
102
103
|
"no_status: No such file or directory\n",
|
103
104
|
"unknown: No such file or directory\n"
|
104
|
-
|
105
|
-
|
105
|
+
)
|
106
|
+
raise( exc, nil, caller(2) )
|
107
|
+
end
|
106
108
|
|
107
109
|
expect( exception ).to be_multiple
|
108
110
|
expect( exception.message ).to eq( <<~ERROR_MESSAGE )
|
@@ -112,80 +114,24 @@ RSpec.describe Hglib do
|
|
112
114
|
ERROR_MESSAGE
|
113
115
|
end
|
114
116
|
|
115
|
-
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
describe "version info" do
|
120
|
-
|
121
|
-
let( :version_info ) {[{
|
122
|
-
extensions: [
|
123
|
-
{bundled: true, name: "churn", ver: nil},
|
124
|
-
{bundled: true, name: "convert", ver: nil},
|
125
|
-
{bundled: false, name: "evolve", ver: "9.2.0"},
|
126
|
-
{bundled: true, name: "extdiff", ver: nil},
|
127
|
-
{bundled: true, name: "gpg", ver: nil},
|
128
|
-
{bundled: false, name: "hggit", ver: "0.8.12 (dulwich 0.19.10)"},
|
129
|
-
{bundled: true, name: "strip", ver: nil},
|
130
|
-
{bundled: true, name: "mq", ver: nil},
|
131
|
-
{bundled: false, name: "prompt", ver: nil},
|
132
|
-
{bundled: true, name: "purge", ver: nil},
|
133
|
-
{bundled: true, name: "rebase", ver: nil},
|
134
|
-
{bundled: false, name: "topic", ver: "0.17.0"},
|
135
|
-
{bundled: true, name: "histedit", ver: nil}
|
136
|
-
],
|
137
|
-
ver: "5.1.1"
|
138
|
-
}]}
|
139
|
-
|
140
|
-
let( :server ) { instance_double(Hglib::Server, stop: nil) }
|
141
|
-
|
142
|
-
|
143
|
-
before( :each ) do
|
144
|
-
described_class.reset_server
|
145
|
-
allow( Hglib::Server ).to receive( :new ).and_return( server )
|
146
|
-
expect( server ).to receive( :run_with_json_template ).
|
147
|
-
with( :version ).
|
148
|
-
and_return( version_info ).
|
149
|
-
at_least( :once )
|
150
|
-
end
|
151
|
-
after( :each ) do
|
152
|
-
described_class.reset_server
|
153
|
-
end
|
154
|
-
|
155
117
|
|
156
|
-
it "can
|
157
|
-
|
118
|
+
it "can be created with additional details" do
|
119
|
+
exception = rescued do
|
120
|
+
exc = Hglib::CommandError.new(
|
121
|
+
:sigs,
|
122
|
+
"hg sigs: option -T not recognized\n",
|
123
|
+
details: "hg sigs\n\nlist signed changesets\n\noptions:\n\n" +
|
124
|
+
" --mq operate on patch repository\n\n(use 'hg sigs -h'" +
|
125
|
+
" to show more help)\n"
|
126
|
+
)
|
127
|
+
raise( exc, nil, caller(2) )
|
128
|
+
end
|
158
129
|
|
159
|
-
expect(
|
160
|
-
end
|
161
|
-
|
162
|
-
|
163
|
-
it "can fetch the simple version of Mercurial" do
|
164
|
-
result = described_class.version
|
165
|
-
|
166
|
-
expect( result ).to eq( version_info.first[:ver] )
|
167
|
-
end
|
168
|
-
|
169
|
-
|
170
|
-
it "can fetch the versions of all loaded Mercurial extensions" do
|
171
|
-
result = described_class.extension_versions
|
172
|
-
|
173
|
-
expect( result ).to be_a( Hash )
|
174
|
-
expect( result ).to include(
|
175
|
-
churn: {bundled: true, ver: nil},
|
176
|
-
evolve: {bundled: false, ver: '9.2.0'},
|
177
|
-
topic: {bundled: false, ver: '0.17.0'},
|
178
|
-
hggit: {bundled: false, ver: "0.8.12 (dulwich 0.19.10)"}
|
179
|
-
)
|
180
|
-
end
|
181
|
-
|
182
|
-
|
183
|
-
it "knows if a given extension is enabled" do
|
184
|
-
expect( described_class.extension_enabled?('topic') ).to be_truthy
|
185
|
-
expect( described_class.extension_enabled?('keyword') ).to be_falsey
|
130
|
+
expect( exception.details ).to match( /list signed changesets/i )
|
186
131
|
end
|
187
132
|
|
188
133
|
end
|
189
134
|
|
135
|
+
|
190
136
|
end
|
191
137
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hglib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Granger
|
@@ -34,7 +34,7 @@ cert_chain:
|
|
34
34
|
jBZSA+N+xUTgUWpXjjwsLZjzJkhWATJWq+krNXcqpwXo6HsjmdUxoFMt63RBb+sI
|
35
35
|
XrxOxp8o0uOkU7FdLSGsyqJ2LzsR4obN
|
36
36
|
-----END CERTIFICATE-----
|
37
|
-
date: 2019-10-
|
37
|
+
date: 2019-10-14 00:00:00.000000000 Z
|
38
38
|
dependencies:
|
39
39
|
- !ruby/object:Gem::Dependency
|
40
40
|
name: loggability
|
@@ -56,14 +56,14 @@ dependencies:
|
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '0.
|
59
|
+
version: '0.2'
|
60
60
|
type: :development
|
61
61
|
prerelease: false
|
62
62
|
version_requirements: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
64
|
- - "~>"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '0.
|
66
|
+
version: '0.2'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: simplecov
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,19 +79,19 @@ dependencies:
|
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: '0.7'
|
81
81
|
- !ruby/object:Gem::Dependency
|
82
|
-
name: rdoc-generator-
|
82
|
+
name: rdoc-generator-fivefish
|
83
83
|
requirement: !ruby/object:Gem::Requirement
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '0'
|
87
|
+
version: '0.4'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: '0'
|
94
|
+
version: '0.4'
|
95
95
|
description: |-
|
96
96
|
This is a client library for the Mercurial distributed revision control tool
|
97
97
|
that uses the {Command Server}[https://www.mercurial-scm.org/wiki/CommandServer] for efficiency.
|
@@ -106,19 +106,27 @@ files:
|
|
106
106
|
- README.md
|
107
107
|
- lib/hglib.rb
|
108
108
|
- lib/hglib/config.rb
|
109
|
+
- lib/hglib/extension.rb
|
110
|
+
- lib/hglib/extension/gpg.rb
|
109
111
|
- lib/hglib/mixins.rb
|
110
112
|
- lib/hglib/repo.rb
|
111
113
|
- lib/hglib/repo/bookmark.rb
|
112
114
|
- lib/hglib/repo/id.rb
|
113
115
|
- lib/hglib/repo/log_entry.rb
|
116
|
+
- lib/hglib/repo/status_entry.rb
|
114
117
|
- lib/hglib/repo/tag.rb
|
115
118
|
- lib/hglib/server.rb
|
119
|
+
- lib/hglib/version_info.rb
|
116
120
|
- spec/hglib/config_spec.rb
|
121
|
+
- spec/hglib/extension/gpg_spec.rb
|
122
|
+
- spec/hglib/extension_spec.rb
|
117
123
|
- spec/hglib/mixins_spec.rb
|
118
124
|
- spec/hglib/repo/id_spec.rb
|
119
125
|
- spec/hglib/repo/log_entry_spec.rb
|
126
|
+
- spec/hglib/repo/status_entry_spec.rb
|
120
127
|
- spec/hglib/repo_spec.rb
|
121
128
|
- spec/hglib/server_spec.rb
|
129
|
+
- spec/hglib/version_info_spec.rb
|
122
130
|
- spec/hglib_spec.rb
|
123
131
|
- spec/spec_helper.rb
|
124
132
|
homepage: https://hg.sr.ht/~ged/hglib
|
@@ -140,7 +148,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
148
|
- !ruby/object:Gem::Version
|
141
149
|
version: '0'
|
142
150
|
requirements: []
|
143
|
-
rubygems_version: 3.0.
|
151
|
+
rubygems_version: 3.0.3
|
144
152
|
signing_key:
|
145
153
|
specification_version: 4
|
146
154
|
summary: This is a client library for the Mercurial distributed revision control tool
|
metadata.gz.sig
CHANGED
Binary file
|