p4ruby 2015.2.1265122-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
data/ext/P4/specmgr.h ADDED
@@ -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
+
data/lib/2.0/P4.so ADDED
Binary file
data/lib/2.1/P4.so ADDED
Binary file
data/lib/2.2/P4.so ADDED
Binary file
data/lib/P4.rb ADDED
@@ -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