p4ruby 2015.2.1265122-x86-mingw32

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.
@@ -0,0 +1,102 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2001-2008, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : specmgr.h
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : Ruby bindings for the Perforce API. Class for handling
34
+ * Perforce specs. This class provides other classes with
35
+ * generic support for parsing and formatting Perforce
36
+ * specs.
37
+ *
38
+ ******************************************************************************/
39
+
40
+ class StrBufDict;
41
+ class SpecMgr
42
+ {
43
+ public:
44
+ SpecMgr();
45
+ ~SpecMgr();
46
+ void SetDebug( int i ) { debug = i; }
47
+
48
+ // Clear the spec cache and revert to internal defaults
49
+ void Reset();
50
+
51
+ // Add a spec to the cache
52
+ void AddSpecDef( const char *type, StrPtr &specDef );
53
+ void AddSpecDef( const char *type, const char * specDef );
54
+
55
+ // Check that a type of spec is known.
56
+ int HaveSpecDef( const char *type );
57
+
58
+ //
59
+ // Parse routine: converts strings into Ruby P4::Spec objects.
60
+ //
61
+ VALUE StringToSpec( const char *type, const char *spec, Error *e );
62
+
63
+ //
64
+ // Format routine. updates a StrBuf object with the form;
65
+ // that can then be converted to a Ruby string where required.
66
+ //
67
+ void SpecToString(const char *type, VALUE hash, StrBuf &b, Error *e);
68
+
69
+ //
70
+ // Convert a Perforce StrDict into a Ruby hash. Used when we're
71
+ // parsing tagged output that is NOT a spec. e.g. output of
72
+ // fstat etc.
73
+ //
74
+ VALUE StrDictToHash( StrDict *dict, VALUE hash = Qnil );
75
+
76
+ //
77
+ // Convert a Perforce StrDict into a P4::Spec object. This is for
78
+ // 2005.2 and later servers where the forms are supplied pre-parsed
79
+ // into a dictionary - we just need to convert them. The specDef
80
+ // argument tells us what type of spec we're converting.
81
+ //
82
+ VALUE StrDictToSpec( StrDict *dict, StrPtr *specDef );
83
+
84
+
85
+ //
86
+ // Return a list of the fields in a given type of spec. Return Qnil
87
+ // if the spec type is not known.
88
+ //
89
+ VALUE SpecFields( const char *type );
90
+
91
+ private:
92
+
93
+ void SplitKey( const StrPtr *key, StrBuf &base, StrBuf &index );
94
+ void InsertItem( VALUE hash, const StrPtr *var, const StrPtr *val );
95
+ VALUE NewSpec( StrPtr *specDef );
96
+ VALUE SpecFields( StrPtr *specDef );
97
+
98
+ private:
99
+ int debug;
100
+ StrBufDict * specs;
101
+ };
102
+
@@ -0,0 +1,64 @@
1
+ /*******************************************************************************
2
+
3
+ Copyright (c) 2001-2008, Perforce Software, Inc. All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright
12
+ notice, this list of conditions and the following disclaimer in the
13
+ documentation and/or other materials provided with the distribution.
14
+
15
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+
26
+ *******************************************************************************/
27
+
28
+ /*******************************************************************************
29
+ * Name : undefdups.h
30
+ *
31
+ * Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
32
+ *
33
+ * Description : Undefine portability macros defined by both Ruby's header
34
+ * files and those of the Perforce API. The idea is that you
35
+ * first include Ruby's headers, then this file, and then the
36
+ * Perforce API. This squelches any compiler warnings about
37
+ * pre-processor macros already being defined.
38
+ *
39
+ ******************************************************************************/
40
+
41
+ //
42
+ // Symbols defined by both Ruby and Perforce API headers
43
+ //
44
+ #undef HAVE_FSYNC
45
+ #undef HAVE_TRUNCATE
46
+
47
+ #ifdef OS_NT
48
+
49
+ // Stupid "#define SetPort SetPortA" in winspool.h
50
+ # ifdef SetPort
51
+ # undef SetPort
52
+ # endif
53
+
54
+ // GetMessage often #defined to GetMessageA
55
+ # ifdef GetMessage
56
+ # undef GetMessage
57
+ # endif
58
+
59
+ #endif
60
+
61
+ #ifdef HAVE_FORK
62
+ # undef HAVE_FORK
63
+ #endif
64
+
Binary file
Binary file
Binary file
@@ -0,0 +1,672 @@
1
+ #*******************************************************************************
2
+ # vim:ts=2:sw=2:et:
3
+ # Copyright (c) 2001-2008, Perforce Software, Inc. All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are met:
7
+ #
8
+ # 1. Redistributions of source code must retain the above copyright
9
+ # notice, this list of conditions and the following disclaimer.
10
+ #
11
+ # 2. Redistributions in binary form must reproduce the above copyright
12
+ # notice, this list of conditions and the following disclaimer in the
13
+ # documentation and/or other materials provided with the distribution.
14
+ #
15
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
+ # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY
19
+ # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20
+ # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21
+ # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22
+ # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23
+ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
+ #*******************************************************************************
26
+
27
+ #*******************************************************************************
28
+ #* Ruby interface to the Perforce SCM System
29
+ #*******************************************************************************
30
+
31
+ #*******************************************************************************
32
+ #* P4 class
33
+ #*******************************************************************************
34
+
35
+ require 'P4/version'
36
+
37
+ #
38
+ # Get the bulk of the definition of the P4 class from the API interface.
39
+ #
40
+ # If this is our precompiled gem, the shared library will lie underneath a
41
+ # a version specific folder.
42
+ #
43
+ begin
44
+ RUBY_VERSION =~ /(\d+\.\d+)/
45
+ require "#{$1}/P4.so"
46
+ rescue LoadError
47
+ require 'P4.so'
48
+ end
49
+
50
+ #
51
+ # Add the extra's written purely in ruby.
52
+ #
53
+ class P4
54
+
55
+ #
56
+ # Named constants for the exception levels. Note they are cumulative,
57
+ # so RAISE_ALL includes RAISE_ERRORS (as you'd expect).
58
+ #
59
+ RAISE_NONE = 0
60
+ RAISE_ERRORS = 1
61
+ RAISE_ALL = 2
62
+
63
+ #
64
+ # Named values for merge actions. Values taken from clientmerge.h in
65
+ # the Perforce API
66
+ #
67
+ MERGE_SKIP = 1
68
+ MERGE_ACCEPT_MERGED = 2
69
+ MERGE_ACCEPT_EDIT = 3
70
+ MERGE_ACCEPT_THEIRS = 4
71
+ MERGE_ACCEPT_YOURS = 5
72
+
73
+ # Named values for generic error codes returned by
74
+ # P4::Message#generic
75
+
76
+ EV_NONE = 0 # misc
77
+
78
+ # The fault of the user
79
+
80
+ EV_USAGE = 0x01 # request not consistent with dox
81
+ EV_UNKNOWN = 0x02 # using unknown entity
82
+ EV_CONTEXT = 0x03 # using entity in wrong context
83
+ EV_ILLEGAL = 0x04 # trying to do something you can't
84
+ EV_NOTYET = 0x05 # something must be corrected first
85
+ EV_PROTECT = 0x06 # protections prevented operation
86
+
87
+ # No fault at all
88
+
89
+ EV_EMPTY = 0x11 # action returned empty results
90
+
91
+ # not the fault of the user
92
+
93
+ EV_FAULT = 0x21 # inexplicable program fault
94
+ EV_CLIENT = 0x22 # client side program errors
95
+ EV_ADMIN = 0x23 # server administrative action required
96
+ EV_CONFIG = 0x24 # client configuration inadequate
97
+ EV_UPGRADE = 0x25 # client or server too old to interact
98
+ EV_COMM = 0x26 # communications error
99
+ EV_TOOBIG = 0x27 # not even Perforce can handle this much
100
+
101
+ # Named values for error severities returned by
102
+ # P4::Message#severity
103
+ E_EMPTY = 0 # nothing yet
104
+ E_INFO = 1 # something good happened
105
+ E_WARN = 2 # something not good happened
106
+ E_FAILED = 3 # user did something wrong
107
+ E_FATAL = 4 # system broken -- nothing can continue
108
+
109
+ # OutputHandler return values constants
110
+
111
+ REPORT = 0
112
+ HANDLED = 1
113
+ CANCEL = 2
114
+
115
+ # Client progress 'done' state
116
+ PROG_NORMAL = 0
117
+ PROG_DONE = 1
118
+ PROG_FAILDONE = 2
119
+ PROG_FLUSH = 3
120
+
121
+ # Mappings for P4#each_<spec>
122
+ # Hash of type vs. key
123
+ SpecTypes = {
124
+ "clients" => ["client", "client"],
125
+ "labels" => ["label", "label"],
126
+ "branches" => ["branch", "branch"],
127
+ "changes" => ["change", "change"],
128
+ "streams" => ["stream", "Stream"],
129
+ "jobs" => ["job", "Job"],
130
+ "users" => ["user", "User"],
131
+ "groups" => ["group", "group"],
132
+ "depots" => ["depot", "name"],
133
+ "servers" => ["server", "Name"],
134
+ }
135
+
136
+ def method_missing( m, *a )
137
+
138
+ # Generic run_* methods
139
+ if ( m.to_s =~ /^run_(.*)/ )
140
+ return self.run( $1, a )
141
+
142
+ # Generic fetch_* methods
143
+ elsif ( m.to_s =~ /^fetch_(.*)/ )
144
+ return self.run( $1, "-o", a ).shift
145
+
146
+ # Generic save_* methods
147
+ elsif ( m.to_s =~ /^save_(.*)/ )
148
+ if ( a.length == 0 )
149
+ raise( P4Exception, "Method P4##{m.to_s} requires an argument", caller)
150
+ end
151
+ self.input = a.shift
152
+ return self.run( $1, "-i", a )
153
+
154
+ # Generic delete_* methods
155
+ elsif ( m.to_s =~ /^delete_(.*)/ )
156
+ if ( a.length == 0 )
157
+ raise( P4Exception, "Method P4##{m.to_s} requires an argument", caller)
158
+ end
159
+ return self.run( $1, "-d", a )
160
+
161
+ # Generic parse_* methods
162
+ elsif ( m.to_s == "parse_forms" )
163
+ raise( NoMethodError, "undefined method 'P4#parse_forms'", caller )
164
+ elsif ( m.to_s =~ /^parse_(.*)/ )
165
+ if ( a.length != 1 )
166
+ raise( P4Exception, "Method P4##{m.to_s} requires an argument", caller)
167
+ end
168
+ return self.parse_spec( $1, a.shift )
169
+
170
+ # Generic format_* methods
171
+ elsif ( m.to_s =~ /^format_(.*)/ )
172
+ if ( a.length != 1 )
173
+ raise( P4Exception, "Method P4##{m.to_s} requires an argument", caller)
174
+ end
175
+ return self.format_spec( $1, a.shift )
176
+
177
+ #
178
+ # Generic each_* methods
179
+ # Simple method to iterate over a particular type of spec
180
+ # This is a convenient wrapper for the pattern:
181
+ # clients = p4.run_clients
182
+ # clients.each do
183
+ # |c|
184
+ # client = p4.fetch_client( c['client'] )
185
+ # <do something with client>
186
+ # end
187
+ #
188
+ # NOTE: It's not possible to implicitly pass a block to a
189
+ # delegate method, so I've implemented it here directly. Could use
190
+ # Proc.new.call, but it looks like there is a serious performance
191
+ # impact with that method.
192
+ #
193
+ elsif ( m.to_s =~ /^each_(.*)/ )
194
+ raise( P4Exception, "No such method P4##{m.to_s}", caller) unless SpecTypes.has_key?( $1 )
195
+ raise( P4Exception, "Method P4##{m.to_s} requires block", caller) unless block_given?
196
+ specs = self.run( $1, a )
197
+ cmd = SpecTypes[ $1 ][0].downcase
198
+ key = SpecTypes[ $1 ][1]
199
+
200
+ specs.each{
201
+ |spec|
202
+ spec = self.run( cmd, "-o", spec[key] ).shift
203
+ yield spec
204
+ }
205
+ return specs
206
+
207
+ # That's all folks!
208
+ else
209
+ raise NameError, "No such method #{m.to_s} in class P4", caller
210
+ end
211
+ end
212
+
213
+ #
214
+ # Simple interface for submitting. If any argument is a Hash, (or subclass
215
+ # thereof - like P4::Spec), then it will be assumed to contain the change
216
+ # form. All other arguments are passed on to the server unchanged.
217
+ #
218
+ def run_submit( *args )
219
+ form = nil
220
+ nargs = args.flatten.collect do
221
+ |a|
222
+ if( a.kind_of?( Hash ) )
223
+ form = a
224
+ nil
225
+ else
226
+ a
227
+ end
228
+ end.compact
229
+
230
+ if( form )
231
+ self.input = form
232
+ nargs.push( "-i" )
233
+ end
234
+ return self.run( "submit", nargs )
235
+ end
236
+
237
+ #
238
+ # Simple interface for shelving. Same rules as for submit apply
239
+
240
+ def run_shelve( *args )
241
+ form = nil
242
+ nargs = args.flatten.collect do
243
+ |a|
244
+ if( a.kind_of?( Hash ) )
245
+ form = a
246
+ nil
247
+ else
248
+ a
249
+ end
250
+ end.compact
251
+
252
+ if( form )
253
+ self.input = form
254
+ nargs.push( "-i" )
255
+ end
256
+ return self.run( "shelve", nargs )
257
+ end
258
+
259
+ def delete_shelve( *args )
260
+ if( ! args.include?( "-c" ) )
261
+ args.unshift( "-c")
262
+ end
263
+ return self.run( "shelve", "-d", args)
264
+ end
265
+
266
+ #
267
+ # Simple interface for using "p4 login"
268
+ #
269
+ def run_login( *args )
270
+ self.input = self.password
271
+ return self.run( "login", args )
272
+ end
273
+
274
+ def run_resolve( *args )
275
+ if( block_given? )
276
+ self.run( "resolve", args ) do
277
+ |default|
278
+ yield( default )
279
+ end
280
+ else
281
+ self.run( "resolve", args )
282
+ end
283
+ end
284
+
285
+ #
286
+ # Simple interface to 'p4 tickets'
287
+ #
288
+ def run_tickets
289
+ path = self.ticket_file
290
+ # return an empty array if the file doesn't exist
291
+ # or is a directory.
292
+ results = Array.new
293
+ re = Regexp.new( /([^=]*)=(.*):([^:]*)$/ )
294
+ if( File.exist?( path ) and !File.directory?( path ) )
295
+ File.open( path ) do
296
+ |file|
297
+ file.each_line do
298
+ |line|
299
+ res = re.match( line )
300
+ if( res )
301
+ tickets = { 'Host' => res[1], 'User' => res[2], 'Ticket' => res[3] }
302
+ results.push( tickets )
303
+ end
304
+ end
305
+ end
306
+ end
307
+ return results
308
+ end
309
+
310
+ #
311
+ # Interface for changing the user's password. Supply the old password
312
+ # and the new one.
313
+ #
314
+ def run_password( oldpass, newpass )
315
+ if( oldpass && oldpass.length > 0 )
316
+ self.input = [ oldpass, newpass, newpass ]
317
+ else
318
+ self.input = [ newpass, newpass ]
319
+ end
320
+ self.run( "password" )
321
+ end
322
+
323
+ #
324
+ # The following methods convert the standard output of some common
325
+ # Perforce commands into more structured form to make using the
326
+ # data easier.
327
+ #
328
+ # (Currently only run_filelog is defined. More to follow)
329
+
330
+ #
331
+ # run_filelog: convert "p4 filelog" responses into objects with useful
332
+ # methods
333
+ #
334
+ # Requires tagged output to be of any real use. If tagged output it not
335
+ # enabled then you just get the raw data back
336
+ #
337
+ def run_filelog( *args )
338
+ raw = self.run( 'filelog', args.flatten )
339
+ raw.collect do
340
+ |h|
341
+ if ( ! h.kind_of?( Hash ) )
342
+ h
343
+ else
344
+ df = P4::DepotFile.new( h[ "depotFile" ] )
345
+ h[ "rev" ].each_index do
346
+ |n|
347
+
348
+ # If rev is nil, there's nothing here for us
349
+ next unless h[ "rev" ][ n ]
350
+
351
+ # Create a new revision of this file ready for populating
352
+ r = df.new_revision
353
+
354
+ h.each do
355
+ |key,value|
356
+ next unless( value.kind_of?( Array ) )
357
+ next unless value[ n ]
358
+ next if( value[ n ].kind_of?( Array ) )
359
+ # If the field is the revision time, convert it to a Time object
360
+ value[ n ] = Time.at( value[ n ].to_i ) if key == "time"
361
+ r.set_attribute( key, value[ n ] )
362
+ end
363
+
364
+ # Now if there are any integration records for this revision,
365
+ # add them in too
366
+ next unless ( h[ "how" ] )
367
+ next unless ( h[ "how" ][ n ] )
368
+
369
+ h[ "how" ][ n ].each_index do
370
+ |m|
371
+ how = h[ "how" ][ n ][ m ]
372
+ file = h[ "file" ][ n ][ m ]
373
+ srev = h[ "srev" ][ n ][ m ]
374
+ erev = h[ "erev" ][ n ][ m ]
375
+ srev.gsub!( /^#/, "" )
376
+ erev.gsub!( /^#/, "" )
377
+ srev = ( srev == "none" ? 0 : srev.to_i )
378
+ erev = ( erev == "none" ? 0 : erev.to_i )
379
+
380
+ r.integration( how, file, srev, erev )
381
+ end
382
+ end
383
+ df
384
+ end
385
+ end
386
+ end
387
+
388
+ #
389
+ # Allow the user to run commands at a temporarily altered exception level.
390
+ # Pass the new exception level desired, and a block to be executed at that
391
+ # level.
392
+ #
393
+ def at_exception_level( level )
394
+ return self unless block_given?
395
+ old_level = self.exception_level
396
+ self.exception_level = level
397
+ begin
398
+ yield( self )
399
+ ensure
400
+ self.exception_level = old_level
401
+ end
402
+ self
403
+ end
404
+
405
+ #
406
+ # Allow users to run commands using a specified handler.
407
+ # Pass a handler and the block that will be executed using this handler
408
+ # The handler will be reset to its previous value at the end of this block
409
+ #
410
+ def with_handler( handler )
411
+ return self unless block_given?
412
+ old_handler = self.handler
413
+ self.handler = handler
414
+ begin
415
+ yield( self )
416
+ ensure
417
+ self.handler = old_handler
418
+ end
419
+ self
420
+ end
421
+
422
+ #
423
+ # Show some handy information when using irb
424
+ #
425
+ def inspect
426
+ sprintf( 'P4: [%s] %s@%s (%s)',
427
+ self.port, self.user, self.client,
428
+ self.connected? ? 'connected' : 'not connected' )
429
+ end
430
+
431
+ #*****************************************************************************
432
+ # The P4::Spec class holds the fields in a Perforce spec
433
+ #*****************************************************************************
434
+ class Spec < Hash
435
+ def initialize( fieldmap = nil )
436
+ @fields = fieldmap
437
+ end
438
+
439
+ #
440
+ # Override the default assignment method. This implementation
441
+ # ensures that any fields defined are valid ones for this type of
442
+ # spec.
443
+ #
444
+ def []=( key, value )
445
+ if( self.has_key?( key ) || @fields == nil )
446
+ super( key, value )
447
+ elsif( @fields.has_key?( key.downcase ) )
448
+ super( @fields[ key.downcase ], value )
449
+ else
450
+ raise( P4Exception, "Invalid field: #{key}" )
451
+ end
452
+ end
453
+
454
+ #
455
+ # Return the list of the fields that are permitted in this spec
456
+ #
457
+ def permitted_fields
458
+ @fields.values
459
+ end
460
+
461
+ #
462
+ # Implement accessor methods for the fields in the spec. The accessor
463
+ # methods are all prefixed with '_' to avoid conflicts with the Hash
464
+ # class' namespace. This is a little ugly, but we gain a lot by
465
+ # subclassing Hash so it's worth it.
466
+ #
467
+ def method_missing( m, *a )
468
+ k = m.to_s.downcase
469
+
470
+ # Check if we're being asked for 'to_ary'. If so, raise 'NoMethodError'.
471
+ raise NoMethodError if( k == "to_ary" )
472
+
473
+ if( k[0..0] != "_" )
474
+ raise( RuntimeError,
475
+ "undefined method `#{m.to_s}' for object of " +
476
+ "class #{self.class.to_s}" )
477
+ end
478
+ k = k[ 1..-1 ]
479
+
480
+ if( k =~ /(.*)=$/ )
481
+ if( a.length() == 0 )
482
+ raise( P4Exception, "Method P4##{m} requires an argument" );
483
+ end
484
+
485
+ k = $1
486
+ if( @fields == nil || @fields.has_key?( k ) )
487
+ return self[ @fields[ k ] ] = a.shift
488
+ end
489
+ elsif( self.has_key?( m.to_s ) )
490
+ return self[ m.to_s ]
491
+ elsif( @fields.has_key?( k ) )
492
+ return self[ @fields[ k ] ]
493
+ end
494
+ raise( P4Exception, "Invalid field: #{$1}" )
495
+ end
496
+ end
497
+
498
+ #*****************************************************************************
499
+ #* P4::MergeInfo class
500
+ #*****************************************************************************
501
+
502
+ class MergeInfo
503
+ def initialize( base, yours, theirs, merged, hint )
504
+ @base = base
505
+ @yours = yours
506
+ @theirs = theirs
507
+ @merged = merged
508
+ @hint = hint
509
+ end
510
+
511
+ attr_reader :base, :yours, :theirs, :merged, :hint
512
+ end
513
+
514
+ #*****************************************************************************
515
+ # P4::Integration class
516
+ # P4::Integration objects hold details about the integrations that have
517
+ # been performed on a particular revision. Used primarily with the
518
+ # P4::Revision class
519
+ #*****************************************************************************
520
+ class Integration
521
+ def initialize( how, file, srev, erev )
522
+ @how = how
523
+ @file = file
524
+ @srev = srev
525
+ @erev = erev
526
+ end
527
+
528
+ attr_reader :how, :file, :srev, :erev
529
+ end
530
+
531
+ #*****************************************************************************
532
+ # P4::Revision class
533
+ # Each P4::Revision object holds details about a particular revision
534
+ # of a file. It may also contain the history of any integrations
535
+ # to/from the file
536
+ #*****************************************************************************
537
+
538
+ class Revision
539
+ def initialize( depotFile )
540
+ @depot_file = depotFile
541
+ @integrations = Array.new
542
+ @attributes = Hash.new
543
+ end
544
+
545
+ attr_reader :depot_file
546
+ attr_accessor :integrations
547
+
548
+ def integration( how, file, srev, erev )
549
+ rec = P4::Integration.new( how, file, srev, erev )
550
+ @integrations.push( rec )
551
+ return rec
552
+ end
553
+
554
+ def each_integration
555
+ @integrations.each { |i| yield( i ) }
556
+ end
557
+
558
+ def set_attribute( name, value )
559
+ name = name.downcase
560
+ if( value =~ /^\d+$/ )
561
+ @attributes[ name ] = value.to_i
562
+ else
563
+ @attributes[ name ] = value
564
+ end
565
+ end
566
+
567
+ # Define #type and #type= explicitly as they clash with the
568
+ # deprecated Object#type. As it is deprecated, this clash should
569
+ # disappear in time.
570
+ def type
571
+ @attributes[ 'type' ]
572
+ end
573
+
574
+ def type=( t )
575
+ @attributes[ 'type' ] = t
576
+ end
577
+
578
+ #
579
+ # Generic getters and setters for revision attributes.
580
+ #
581
+ def method_missing( m, *a )
582
+ k = m.to_s.downcase
583
+ if( k =~ /(.*)=$/ )
584
+ if( a.length() == 0 )
585
+ raise( P4Exception, "Method P4##{m} requires an argument" );
586
+ end
587
+ k = $1
588
+ @attributes[ k ] = a.shift
589
+ else
590
+ @attributes[ k ]
591
+ end
592
+ end
593
+ end
594
+
595
+ #*****************************************************************************
596
+ # P4::DepotFile class.
597
+ # Each DepotFile entry contains details about one depot file.
598
+ #*****************************************************************************
599
+ class DepotFile
600
+ def initialize( name )
601
+ @depot_file = name
602
+ @revisions = Array.new
603
+ @headAction = @head_type = @head_time = @head_rev = @head_change = nil
604
+ end
605
+
606
+ attr_reader :depot_file, :revisions
607
+ attr_accessor :head_action, :head_type, :head_time, :head_rev, :head_change
608
+
609
+ def new_revision
610
+ r = P4::Revision.new( @depot_file )
611
+ @revisions.push( r )
612
+ return r
613
+ end
614
+
615
+ def each_revision
616
+ @revisions.each { |r| yield( r ) }
617
+ end
618
+ end
619
+
620
+ #*****************************************************************************
621
+ # P4::OutputHandler class.
622
+ # Base class for all Handler classes that can be passed to P4::handler.
623
+ #*****************************************************************************
624
+ class OutputHandler
625
+ def outputStat(stat)
626
+ REPORT
627
+ end
628
+
629
+ def outputInfo(info)
630
+ REPORT
631
+ end
632
+
633
+ def outputText(text)
634
+ REPORT
635
+ end
636
+
637
+ def outputBinary(binary)
638
+ REPORT
639
+ end
640
+
641
+ def outputMessage(message)
642
+ REPORT
643
+ end
644
+ end
645
+
646
+ class ReportHandler < OutputHandler
647
+ def outputStat(stat)
648
+ p "stat:", stat
649
+ HANDLED
650
+ end
651
+
652
+ def outputInfo(info)
653
+ p "info:", info
654
+ HANDLED
655
+ end
656
+
657
+ def outputText(text)
658
+ p "text:", text
659
+ HANDLED
660
+ end
661
+
662
+ def outputBinary(binary)
663
+ p "binary:", binary
664
+ HANDLED
665
+ end
666
+
667
+ def outputMessage(message)
668
+ p "message:", message
669
+ HANDLED
670
+ end
671
+ end
672
+ end # class P4