hglib 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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