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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b890e1ab00998d1042bb8d586771adfcfe352679da65905af0efd0953368b66b
4
- data.tar.gz: 0710da264e90e0fc3a4be8815ad313b5eff34523c7e070db3ecb1014dcf25efa
3
+ metadata.gz: 8c3e4ce0e0a5a9fae8575225359cc5b8e922cfd009b1ceade3a3ed4f4a9865a9
4
+ data.tar.gz: 5d1e25766012a16829958a194398394eed379555369e36e8c1617641e9ad6da8
5
5
  SHA512:
6
- metadata.gz: 40377af3d802f96c7256e77aca8d6bce7d255aa2cc84e050166079649f16c3454bb5e6c8de2ad3f2086c5ccbf873634db9a071b3f6acf5eb0af9f5629349a0ff
7
- data.tar.gz: e923e390dec969cfa4a5831d242fa0169458d64aafe1b365ab0422f1f85d135e58907cdbedc983391b5d06d55a801396ff9d3a6c35c60d0e93e0814dcf3ec45b
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.4.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
- def initialize( args )
37
- @command = args.shift
38
- @messages = args.flatten.map( &:chomp )
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 for multi-message errors.
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
- ### Fetch a Hash of version information about the Mercurial that is being used.
153
- def self::versions
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
- instance_variable_get( "@#{attrname}" ) ? true : false
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
- response = self.server.run( :diff, *files, **options )
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
- response = self.server.run( :add, *files, **options )
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
- response = self.server.run( :addremove, *files, **options )
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
- response = self.server.run( :commit, *files, **options )
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
- response = self.server.run( :pull, source, **options )
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
- response = self.server.run( :update, rev, **options )
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
- response = self.server.run( :push, destination, **options )
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
- response = self.server.run( :bookmark, *names, **options )
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
- raise Hglib::CommandError, [command, *errors] unless errors.empty?
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
- raise Hglib::CommandError, [:status, "no_status: No such file or directory\n"]
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
- raise Hglib::CommandError, [
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 fetch the versions of Mercurial and loaded extensions" do
157
- result = described_class.versions
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( result ).to eq( version_info.first )
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.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-12 00:00:00.000000000 Z
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.1'
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.1'
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-sixfish
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.6
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