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.
- checksums.yaml +7 -0
- data/LICENSE.txt +24 -0
- data/README.md +866 -0
- data/ext/P4/clientprogressruby.cpp +99 -0
- data/ext/P4/clientprogressruby.h +52 -0
- data/ext/P4/clientuserruby.cpp +726 -0
- data/ext/P4/clientuserruby.h +133 -0
- data/ext/P4/extconf.rb +580 -0
- data/ext/P4/gc_hack.h +10 -0
- data/ext/P4/p4.cpp +1338 -0
- data/ext/P4/p4clientapi.cpp +732 -0
- data/ext/P4/p4clientapi.h +239 -0
- data/ext/P4/p4error.cpp +122 -0
- data/ext/P4/p4error.h +61 -0
- data/ext/P4/p4mapmaker.cpp +459 -0
- data/ext/P4/p4mapmaker.h +69 -0
- data/ext/P4/p4mergedata.cpp +272 -0
- data/ext/P4/p4mergedata.h +97 -0
- data/ext/P4/p4result.cpp +259 -0
- data/ext/P4/p4result.h +86 -0
- data/ext/P4/p4rubydebug.h +46 -0
- data/ext/P4/p4specdata.cpp +108 -0
- data/ext/P4/p4specdata.h +52 -0
- data/ext/P4/p4utils.cpp +62 -0
- data/ext/P4/p4utils.h +46 -0
- data/ext/P4/specmgr.cpp +721 -0
- data/ext/P4/specmgr.h +102 -0
- data/ext/P4/undefdups.h +64 -0
- data/lib/2.0/P4.so +0 -0
- data/lib/2.1/P4.so +0 -0
- data/lib/2.2/P4.so +0 -0
- data/lib/P4.rb +672 -0
- data/lib/P4/version.rb +3 -0
- metadata +75 -0
@@ -0,0 +1,732 @@
|
|
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 : p4clientapi.cc
|
30
|
+
*
|
31
|
+
* Author : Tony Smith <tony@perforce.com> or <tony@smee.org>
|
32
|
+
*
|
33
|
+
* Description : Ruby bindings for the Perforce API. Main interface to the
|
34
|
+
* Perforce API.
|
35
|
+
*
|
36
|
+
******************************************************************************/
|
37
|
+
#include <ruby.h>
|
38
|
+
#include "undefdups.h"
|
39
|
+
#include <p4/clientapi.h>
|
40
|
+
#include <p4/i18napi.h>
|
41
|
+
#include <p4/enviro.h>
|
42
|
+
#include <p4/hostenv.h>
|
43
|
+
#include <p4/spec.h>
|
44
|
+
#include <p4/ignore.h>
|
45
|
+
#include <p4/debug.h>
|
46
|
+
#include "p4result.h"
|
47
|
+
#include "p4rubydebug.h"
|
48
|
+
#include "clientuserruby.h"
|
49
|
+
#include "specmgr.h"
|
50
|
+
#include "p4clientapi.h"
|
51
|
+
#include "p4utils.h"
|
52
|
+
|
53
|
+
|
54
|
+
|
55
|
+
/*******************************************************************************
|
56
|
+
* Our Ruby classes.
|
57
|
+
******************************************************************************/
|
58
|
+
extern VALUE cP4; // Base P4 class
|
59
|
+
extern VALUE eP4; // Exception class
|
60
|
+
|
61
|
+
|
62
|
+
P4ClientApi::P4ClientApi() : ui( &specMgr )
|
63
|
+
{
|
64
|
+
debug = 0;
|
65
|
+
server2 = 0;
|
66
|
+
depth = 0;
|
67
|
+
exceptionLevel = 2;
|
68
|
+
maxResults = 0;
|
69
|
+
maxScanRows = 0;
|
70
|
+
maxLockTime = 0;
|
71
|
+
InitFlags();
|
72
|
+
apiLevel = atoi( P4Tag::l_client );
|
73
|
+
enviro = new Enviro;
|
74
|
+
prog = "unnamed p4ruby script";
|
75
|
+
|
76
|
+
client.SetProtocol( "specstring", "" );
|
77
|
+
|
78
|
+
//
|
79
|
+
// Load any P4CONFIG file
|
80
|
+
//
|
81
|
+
HostEnv henv;
|
82
|
+
StrBuf cwd;
|
83
|
+
|
84
|
+
henv.GetCwd( cwd, enviro );
|
85
|
+
if( cwd.Length() )
|
86
|
+
enviro->Config( cwd );
|
87
|
+
|
88
|
+
//
|
89
|
+
// Load the current ticket file. Start with the default, and then
|
90
|
+
// override it if P4TICKETS is set.
|
91
|
+
//
|
92
|
+
const char *t;
|
93
|
+
|
94
|
+
henv.GetTicketFile( ticketFile );
|
95
|
+
|
96
|
+
if( (t = enviro->Get("P4TICKETS")) )
|
97
|
+
ticketFile = t;
|
98
|
+
|
99
|
+
//
|
100
|
+
// Load the current P4CHARSET if set.
|
101
|
+
//
|
102
|
+
if( client.GetCharset().Length() )
|
103
|
+
SetCharset( client.GetCharset().Text() );
|
104
|
+
}
|
105
|
+
|
106
|
+
P4ClientApi::~P4ClientApi()
|
107
|
+
{
|
108
|
+
if ( IsConnected() )
|
109
|
+
{
|
110
|
+
Error e;
|
111
|
+
client.Final( &e );
|
112
|
+
// Ignore errors
|
113
|
+
}
|
114
|
+
delete enviro;
|
115
|
+
}
|
116
|
+
|
117
|
+
const char *
|
118
|
+
P4ClientApi::GetEnv( const char *v)
|
119
|
+
{
|
120
|
+
return enviro->Get( v );
|
121
|
+
}
|
122
|
+
|
123
|
+
void
|
124
|
+
P4ClientApi::SetEnviroFile( const char *c )
|
125
|
+
{
|
126
|
+
enviro->SetEnviroFile(c);
|
127
|
+
}
|
128
|
+
|
129
|
+
const StrPtr *
|
130
|
+
P4ClientApi::GetEnviroFile()
|
131
|
+
{
|
132
|
+
return enviro->GetEnviroFile();
|
133
|
+
}
|
134
|
+
|
135
|
+
void
|
136
|
+
P4ClientApi::SetApiLevel( int level )
|
137
|
+
{
|
138
|
+
StrBuf b;
|
139
|
+
b << level;
|
140
|
+
apiLevel = level;
|
141
|
+
client.SetProtocol( "api", b.Text() );
|
142
|
+
ui.SetApiLevel( level );
|
143
|
+
}
|
144
|
+
|
145
|
+
int
|
146
|
+
P4ClientApi::SetCharset( const char *c )
|
147
|
+
{
|
148
|
+
StrRef cs_none( "none" );
|
149
|
+
|
150
|
+
if( P4RDB_COMMANDS )
|
151
|
+
fprintf( stderr, "[P4] Setting charset: %s\n", c );
|
152
|
+
|
153
|
+
if( c && cs_none != c )
|
154
|
+
{
|
155
|
+
CharSetApi::CharSet cs = CharSetApi::Lookup( c );
|
156
|
+
if( cs < 0 )
|
157
|
+
{
|
158
|
+
StrBuf m;
|
159
|
+
m = "Unknown or unsupported charset: ";
|
160
|
+
m.Append( c );
|
161
|
+
Except( "P4#charset=", m.Text() );
|
162
|
+
}
|
163
|
+
#ifdef HAVE_RUBY_ENCODING_H
|
164
|
+
CharSetApi::CharSet utf8 = CharSetApi::Lookup( "utf8" );
|
165
|
+
client.SetTrans( utf8, cs, utf8, utf8 );
|
166
|
+
#else
|
167
|
+
client.SetTrans( cs, cs, cs, cs );
|
168
|
+
#endif
|
169
|
+
client.SetCharset( c );
|
170
|
+
P4Utils::SetCharset( c );
|
171
|
+
}
|
172
|
+
else
|
173
|
+
{
|
174
|
+
// Disables automatic unicode detection if called
|
175
|
+
// prior to init (2014.2)
|
176
|
+
client.SetTrans( 0 );
|
177
|
+
}
|
178
|
+
return 1;
|
179
|
+
}
|
180
|
+
|
181
|
+
void
|
182
|
+
P4ClientApi::SetCwd( const char *c )
|
183
|
+
{
|
184
|
+
client.SetCwd( c );
|
185
|
+
enviro->Config( StrRef( c ) );
|
186
|
+
}
|
187
|
+
|
188
|
+
void
|
189
|
+
P4ClientApi::SetTicketFile( const char *p )
|
190
|
+
{
|
191
|
+
client.SetTicketFile( p );
|
192
|
+
ticketFile = p;
|
193
|
+
}
|
194
|
+
|
195
|
+
void
|
196
|
+
P4ClientApi::SetDebug( int d )
|
197
|
+
{
|
198
|
+
debug = d;
|
199
|
+
ui.SetDebug( d );
|
200
|
+
specMgr.SetDebug( d );
|
201
|
+
|
202
|
+
if( P4RDB_RPC )
|
203
|
+
p4debug.SetLevel( "rpc=5" );
|
204
|
+
else
|
205
|
+
p4debug.SetLevel( "rpc=0" );
|
206
|
+
|
207
|
+
if( P4RDB_SSL )
|
208
|
+
p4debug.SetLevel( "ssl=3" );
|
209
|
+
else
|
210
|
+
p4debug.SetLevel( "ssl=0" );
|
211
|
+
}
|
212
|
+
|
213
|
+
void
|
214
|
+
P4ClientApi::SetProtocol( const char *var, const char *val )
|
215
|
+
{
|
216
|
+
client.SetProtocol( var, val );
|
217
|
+
}
|
218
|
+
|
219
|
+
VALUE
|
220
|
+
P4ClientApi::SetEnv( const char *var, const char *val )
|
221
|
+
{
|
222
|
+
Error e;
|
223
|
+
|
224
|
+
enviro->Set( var, val, &e );
|
225
|
+
if( e.Test() && exceptionLevel )
|
226
|
+
{
|
227
|
+
Except( "P4#set_env", &e );
|
228
|
+
}
|
229
|
+
|
230
|
+
if( e.Test() )
|
231
|
+
return Qfalse;
|
232
|
+
|
233
|
+
// Fixes an issue on OS X where the next enviro->Get doesn't return the
|
234
|
+
// cached value
|
235
|
+
enviro->Reload();
|
236
|
+
|
237
|
+
return Qtrue;
|
238
|
+
}
|
239
|
+
|
240
|
+
//
|
241
|
+
// connect to the Perforce server.
|
242
|
+
//
|
243
|
+
|
244
|
+
VALUE
|
245
|
+
P4ClientApi::Connect()
|
246
|
+
{
|
247
|
+
if ( P4RDB_COMMANDS )
|
248
|
+
fprintf( stderr, "[P4] Connecting to Perforce\n" );
|
249
|
+
|
250
|
+
if ( IsConnected() )
|
251
|
+
{
|
252
|
+
rb_warn( "P4#connect - Perforce client already connected!" );
|
253
|
+
return Qtrue;
|
254
|
+
}
|
255
|
+
|
256
|
+
return ConnectOrReconnect();
|
257
|
+
}
|
258
|
+
|
259
|
+
VALUE
|
260
|
+
P4ClientApi::ConnectOrReconnect()
|
261
|
+
{
|
262
|
+
if ( IsTrackMode() )
|
263
|
+
client.SetProtocol( "track", "" );
|
264
|
+
|
265
|
+
Error e;
|
266
|
+
|
267
|
+
ResetFlags();
|
268
|
+
client.Init( &e );
|
269
|
+
if ( e.Test() && exceptionLevel )
|
270
|
+
Except( "P4#connect", &e );
|
271
|
+
|
272
|
+
if ( e.Test() )
|
273
|
+
return Qfalse;
|
274
|
+
|
275
|
+
// If a handler is defined, reset the break functionality
|
276
|
+
// for the KeepAlive function
|
277
|
+
|
278
|
+
if( ui.GetHandler() != Qnil )
|
279
|
+
{
|
280
|
+
client.SetBreak( &ui );
|
281
|
+
}
|
282
|
+
|
283
|
+
SetConnected();
|
284
|
+
return Qtrue;
|
285
|
+
}
|
286
|
+
|
287
|
+
|
288
|
+
//
|
289
|
+
// Disconnect session
|
290
|
+
//
|
291
|
+
VALUE
|
292
|
+
P4ClientApi::Disconnect()
|
293
|
+
{
|
294
|
+
if ( P4RDB_COMMANDS )
|
295
|
+
fprintf( stderr, "[P4] Disconnect\n" );
|
296
|
+
|
297
|
+
if ( !IsConnected() )
|
298
|
+
{
|
299
|
+
rb_warn( "P4#disconnect - not connected" );
|
300
|
+
return Qtrue;
|
301
|
+
}
|
302
|
+
Error e;
|
303
|
+
client.Final( &e );
|
304
|
+
ResetFlags();
|
305
|
+
|
306
|
+
// Clear the specdef cache.
|
307
|
+
specMgr.Reset();
|
308
|
+
|
309
|
+
return Qtrue;
|
310
|
+
}
|
311
|
+
|
312
|
+
//
|
313
|
+
// Test whether or not connected
|
314
|
+
//
|
315
|
+
VALUE
|
316
|
+
P4ClientApi::Connected()
|
317
|
+
{
|
318
|
+
if( IsConnected() && !client.Dropped() )
|
319
|
+
return Qtrue;
|
320
|
+
else if( IsConnected() )
|
321
|
+
Disconnect();
|
322
|
+
return Qfalse;
|
323
|
+
}
|
324
|
+
|
325
|
+
void
|
326
|
+
P4ClientApi::Tagged( int enable )
|
327
|
+
{
|
328
|
+
if( enable )
|
329
|
+
SetTag();
|
330
|
+
else
|
331
|
+
ClearTag();
|
332
|
+
}
|
333
|
+
|
334
|
+
int P4ClientApi::SetTrack( int enable )
|
335
|
+
{
|
336
|
+
if ( IsConnected() ) {
|
337
|
+
if( exceptionLevel )
|
338
|
+
{
|
339
|
+
Except( "P4#track=", "Can't change performance tracking once you've connected.");
|
340
|
+
}
|
341
|
+
return Qfalse;
|
342
|
+
}
|
343
|
+
else if ( enable ) {
|
344
|
+
SetTrackMode();
|
345
|
+
ui.SetTrack(true);
|
346
|
+
}
|
347
|
+
else {
|
348
|
+
ClearTrackMode();
|
349
|
+
ui.SetTrack(false);
|
350
|
+
}
|
351
|
+
return Qtrue;
|
352
|
+
}
|
353
|
+
|
354
|
+
void P4ClientApi::SetStreams( int enable )
|
355
|
+
{
|
356
|
+
if ( enable )
|
357
|
+
SetStreamsMode();
|
358
|
+
else
|
359
|
+
ClearStreamsMode();
|
360
|
+
}
|
361
|
+
|
362
|
+
int
|
363
|
+
P4ClientApi::GetServerLevel()
|
364
|
+
{
|
365
|
+
if( !IsConnected() )
|
366
|
+
Except( "server_level", "Not connected to a Perforce Server.");
|
367
|
+
if( !IsCmdRun() )
|
368
|
+
Run( "info", 0, 0 );
|
369
|
+
return server2;
|
370
|
+
}
|
371
|
+
|
372
|
+
int
|
373
|
+
P4ClientApi::ServerCaseSensitive()
|
374
|
+
{
|
375
|
+
if( !IsConnected() )
|
376
|
+
Except( "server_case_sensitive?", "Not connected to a Perforce Server.");
|
377
|
+
if( !IsCmdRun() )
|
378
|
+
Run( "info", 0, 0);
|
379
|
+
return !IsCaseFold();
|
380
|
+
}
|
381
|
+
|
382
|
+
int
|
383
|
+
P4ClientApi::ServerUnicode()
|
384
|
+
{
|
385
|
+
if( !IsConnected() )
|
386
|
+
Except( "server_unicode?", "Not connected to a Perforce Server.");
|
387
|
+
if( !IsCmdRun() )
|
388
|
+
Run( "info", 0, 0);
|
389
|
+
return IsUnicode();
|
390
|
+
}
|
391
|
+
|
392
|
+
|
393
|
+
// Check if the supplied path falls within the view of the ignore file
|
394
|
+
int
|
395
|
+
P4ClientApi::IsIgnored( const char *path )
|
396
|
+
{
|
397
|
+
Ignore *ignore = client.GetIgnore();
|
398
|
+
if( !ignore ) return 0;
|
399
|
+
|
400
|
+
StrRef p( path );
|
401
|
+
return ignore->Reject( p, client.GetIgnoreFile() );
|
402
|
+
}
|
403
|
+
|
404
|
+
//
|
405
|
+
// Run returns the results of the command. If the client has not been
|
406
|
+
// connected, then an exception is raised but errors from Perforce
|
407
|
+
// commands are returned via the Errors() and ErrorCount() interfaces
|
408
|
+
// and not via exceptions because one failure in a command applied to many
|
409
|
+
// files would interrupt processing of all the other files if an exception
|
410
|
+
// is raised.
|
411
|
+
//
|
412
|
+
|
413
|
+
VALUE
|
414
|
+
P4ClientApi::Run( const char *cmd, int argc, char * const *argv )
|
415
|
+
{
|
416
|
+
// Save the entire command string for our error messages. Makes it
|
417
|
+
// easy to see where a script has gone wrong.
|
418
|
+
StrBuf cmdString;
|
419
|
+
cmdString << "\"p4 " << cmd;
|
420
|
+
for( int i = 0; i < argc; i++ )
|
421
|
+
cmdString << " " << argv[ i ];
|
422
|
+
cmdString << "\"";
|
423
|
+
|
424
|
+
if ( P4RDB_COMMANDS )
|
425
|
+
fprintf( stderr, "[P4] Executing %s\n", cmdString.Text() );
|
426
|
+
|
427
|
+
if ( depth )
|
428
|
+
{
|
429
|
+
rb_warn( "Can't execute nested Perforce commands." );
|
430
|
+
return Qfalse;
|
431
|
+
}
|
432
|
+
|
433
|
+
// Clear out any results from the previous command
|
434
|
+
ui.Reset();
|
435
|
+
|
436
|
+
if ( !IsConnected() && exceptionLevel )
|
437
|
+
Except( "P4#run", "not connected." );
|
438
|
+
|
439
|
+
if ( !IsConnected() )
|
440
|
+
return Qfalse;
|
441
|
+
|
442
|
+
// Tell the UI which command we're running.
|
443
|
+
ui.SetCommand( cmd );
|
444
|
+
|
445
|
+
depth++;
|
446
|
+
RunCmd( cmd, &ui, argc, argv );
|
447
|
+
depth--;
|
448
|
+
|
449
|
+
if( ui.GetHandler() != Qnil) {
|
450
|
+
if( client.Dropped() && ! ui.IsAlive() ) {
|
451
|
+
Disconnect();
|
452
|
+
ConnectOrReconnect();
|
453
|
+
}
|
454
|
+
}
|
455
|
+
|
456
|
+
ui.RaiseRubyException();
|
457
|
+
|
458
|
+
P4Result &results = ui.GetResults();
|
459
|
+
|
460
|
+
if ( results.ErrorCount() && exceptionLevel )
|
461
|
+
Except( "P4#run", "Errors during command execution", cmdString.Text() );
|
462
|
+
|
463
|
+
if ( results.WarningCount() && exceptionLevel > 1 )
|
464
|
+
Except( "P4#run", "Warnings during command execution",cmdString.Text());
|
465
|
+
|
466
|
+
return results.GetOutput();
|
467
|
+
}
|
468
|
+
|
469
|
+
|
470
|
+
void
|
471
|
+
P4ClientApi::RunCmd( const char *cmd, ClientUser *ui, int argc, char * const *argv )
|
472
|
+
{
|
473
|
+
client.SetProg( &prog );
|
474
|
+
if( version.Length() )
|
475
|
+
client.SetVersion( &version );
|
476
|
+
|
477
|
+
if( IsTag() )
|
478
|
+
client.SetVar( "tag" );
|
479
|
+
|
480
|
+
if ( IsStreams() && apiLevel > 69 )
|
481
|
+
client.SetVar( "enableStreams", "" );
|
482
|
+
|
483
|
+
// If maxresults or maxscanrows is set, enforce them now
|
484
|
+
if( maxResults ) client.SetVar( "maxResults", maxResults );
|
485
|
+
if( maxScanRows ) client.SetVar( "maxScanRows", maxScanRows );
|
486
|
+
if( maxLockTime ) client.SetVar( "maxLockTime", maxLockTime );
|
487
|
+
|
488
|
+
// If progress is set, set progress var.
|
489
|
+
if( ( (ClientUserRuby*)ui)->GetProgress() != Qnil ) client.SetVar( P4Tag::v_progress, 1 );
|
490
|
+
|
491
|
+
client.SetArgv( argc, argv );
|
492
|
+
client.Run( cmd, ui );
|
493
|
+
|
494
|
+
// Can only read the protocol block *after* a command has been run.
|
495
|
+
// Do this once only.
|
496
|
+
if( !IsCmdRun() )
|
497
|
+
{
|
498
|
+
StrPtr *s = 0;
|
499
|
+
if ( (s = client.GetProtocol(P4Tag::v_server2)) )
|
500
|
+
server2 = s->Atoi();
|
501
|
+
|
502
|
+
if( (s = client.GetProtocol(P4Tag::v_unicode)) )
|
503
|
+
if( s->Atoi() )
|
504
|
+
SetUnicode();
|
505
|
+
|
506
|
+
if( (s = client.GetProtocol(P4Tag::v_nocase)) )
|
507
|
+
SetCaseFold();
|
508
|
+
}
|
509
|
+
SetCmdRun();
|
510
|
+
}
|
511
|
+
|
512
|
+
|
513
|
+
//
|
514
|
+
// Parses a string supplied by the user into a hash. To do this we need
|
515
|
+
// the specstring from the server. We try to cache those as we see them,
|
516
|
+
// but the user may not have executed any commands to allow us to cache
|
517
|
+
// them so we may have to fetch the spec first.
|
518
|
+
//
|
519
|
+
|
520
|
+
VALUE
|
521
|
+
P4ClientApi::ParseSpec( const char * type, const char *form )
|
522
|
+
{
|
523
|
+
if ( !specMgr.HaveSpecDef( type ) )
|
524
|
+
{
|
525
|
+
if( exceptionLevel )
|
526
|
+
{
|
527
|
+
StrBuf m;
|
528
|
+
m = "No spec definition for ";
|
529
|
+
m.Append( type );
|
530
|
+
m.Append( " objects." );
|
531
|
+
Except( "P4#parse_spec", m.Text() );
|
532
|
+
}
|
533
|
+
else
|
534
|
+
{
|
535
|
+
return Qfalse;
|
536
|
+
}
|
537
|
+
}
|
538
|
+
|
539
|
+
// Got a specdef so now we can attempt to parse it.
|
540
|
+
Error e;
|
541
|
+
VALUE v;
|
542
|
+
v = specMgr.StringToSpec( type, form, &e );
|
543
|
+
|
544
|
+
if ( e.Test() )
|
545
|
+
{
|
546
|
+
if( exceptionLevel )
|
547
|
+
Except( "P4#parse_spec", &e );
|
548
|
+
else
|
549
|
+
return Qfalse;
|
550
|
+
}
|
551
|
+
|
552
|
+
return v;
|
553
|
+
}
|
554
|
+
|
555
|
+
|
556
|
+
//
|
557
|
+
// Converts a hash supplied by the user into a string using the specstring
|
558
|
+
// from the server. We may have to fetch the specstring first.
|
559
|
+
//
|
560
|
+
|
561
|
+
VALUE
|
562
|
+
P4ClientApi::FormatSpec( const char * type, VALUE hash )
|
563
|
+
{
|
564
|
+
if ( !specMgr.HaveSpecDef( type ) )
|
565
|
+
{
|
566
|
+
if( exceptionLevel )
|
567
|
+
{
|
568
|
+
StrBuf m;
|
569
|
+
m = "No spec definition for ";
|
570
|
+
m.Append( type );
|
571
|
+
m.Append( " objects." );
|
572
|
+
Except( "P4#format_spec", m.Text() );
|
573
|
+
}
|
574
|
+
else
|
575
|
+
{
|
576
|
+
return Qfalse;
|
577
|
+
}
|
578
|
+
}
|
579
|
+
|
580
|
+
// Got a specdef so now we can attempt to convert.
|
581
|
+
StrBuf buf;
|
582
|
+
Error e;
|
583
|
+
|
584
|
+
specMgr.SpecToString( type, hash, buf, &e );
|
585
|
+
if( !e.Test() )
|
586
|
+
return P4Utils::ruby_string( buf.Text() );
|
587
|
+
|
588
|
+
if( exceptionLevel )
|
589
|
+
{
|
590
|
+
StrBuf m;
|
591
|
+
m = "Error converting hash to a string.";
|
592
|
+
if( e.Test() ) e.Fmt( m, EF_PLAIN );
|
593
|
+
Except( "P4#format_spec", m.Text() );
|
594
|
+
}
|
595
|
+
return Qnil;
|
596
|
+
}
|
597
|
+
|
598
|
+
//
|
599
|
+
// Returns a hash whose keys contain the names of the fields in a spec of the
|
600
|
+
// specified type. Not yet exposed to Ruby clients, but may be in future.
|
601
|
+
//
|
602
|
+
VALUE
|
603
|
+
P4ClientApi::SpecFields( const char * type )
|
604
|
+
{
|
605
|
+
if ( !specMgr.HaveSpecDef( type ) )
|
606
|
+
{
|
607
|
+
if( exceptionLevel )
|
608
|
+
{
|
609
|
+
StrBuf m;
|
610
|
+
m = "No spec definition for ";
|
611
|
+
m.Append( type );
|
612
|
+
m.Append( " objects." );
|
613
|
+
Except( "P4#spec_fields", m.Text() );
|
614
|
+
}
|
615
|
+
else
|
616
|
+
{
|
617
|
+
return Qfalse;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
|
621
|
+
return specMgr.SpecFields( type );
|
622
|
+
}
|
623
|
+
|
624
|
+
//
|
625
|
+
// Raises an exception or returns Qfalse on bad input
|
626
|
+
//
|
627
|
+
|
628
|
+
VALUE
|
629
|
+
P4ClientApi::SetInput( VALUE input )
|
630
|
+
{
|
631
|
+
if ( P4RDB_COMMANDS )
|
632
|
+
fprintf( stderr, "[P4] Received input for next command\n" );
|
633
|
+
|
634
|
+
if ( ! ui.SetInput( input ) )
|
635
|
+
{
|
636
|
+
if ( exceptionLevel )
|
637
|
+
Except( "P4#input", "Error parsing supplied data." );
|
638
|
+
else
|
639
|
+
return Qfalse;
|
640
|
+
}
|
641
|
+
return Qtrue;
|
642
|
+
}
|
643
|
+
|
644
|
+
//
|
645
|
+
// Sets the handler and connects the SetBreak feature
|
646
|
+
//
|
647
|
+
VALUE
|
648
|
+
P4ClientApi::SetHandler( VALUE handler )
|
649
|
+
{
|
650
|
+
if ( P4RDB_COMMANDS )
|
651
|
+
fprintf( stderr, "[P4] Received handler object\n" );
|
652
|
+
|
653
|
+
ui.SetHandler( handler );
|
654
|
+
|
655
|
+
if( handler == Qnil)
|
656
|
+
client.SetBreak(NULL);
|
657
|
+
else
|
658
|
+
client.SetBreak(&ui);
|
659
|
+
|
660
|
+
return Qtrue;
|
661
|
+
}
|
662
|
+
|
663
|
+
VALUE
|
664
|
+
P4ClientApi::SetProgress( VALUE progress ) {
|
665
|
+
if ( P4RDB_COMMANDS )
|
666
|
+
fprintf( stderr, "[P4] Received progress object\n" );
|
667
|
+
|
668
|
+
return ui.SetProgress( progress );
|
669
|
+
}
|
670
|
+
|
671
|
+
|
672
|
+
void
|
673
|
+
P4ClientApi::GCMark()
|
674
|
+
{
|
675
|
+
if ( P4RDB_GC )
|
676
|
+
fprintf( stderr, "[P4] Ruby asked us to do garbage collection\n" );
|
677
|
+
|
678
|
+
// We don't hold Ruby objects. But our UI does.
|
679
|
+
ui.GCMark();
|
680
|
+
}
|
681
|
+
|
682
|
+
void
|
683
|
+
P4ClientApi::Except( const char *func, const char *msg )
|
684
|
+
{
|
685
|
+
StrBuf m;
|
686
|
+
StrBuf errors;
|
687
|
+
StrBuf warnings;
|
688
|
+
int terminate = 0;
|
689
|
+
|
690
|
+
m << "[" << func << "] " << msg;
|
691
|
+
|
692
|
+
// Now append any errors and warnings to the text
|
693
|
+
ui.GetResults().FmtErrors( errors );
|
694
|
+
ui.GetResults().FmtWarnings( warnings );
|
695
|
+
|
696
|
+
if( errors.Length() )
|
697
|
+
{
|
698
|
+
m << "\n" << errors;
|
699
|
+
terminate++;
|
700
|
+
}
|
701
|
+
|
702
|
+
if( exceptionLevel > 1 && warnings.Length() )
|
703
|
+
{
|
704
|
+
m << "\n" << warnings;
|
705
|
+
terminate++;
|
706
|
+
}
|
707
|
+
|
708
|
+
if( terminate )
|
709
|
+
m << "\n\n";
|
710
|
+
|
711
|
+
rb_raise( eP4, "%s", m.Text() );
|
712
|
+
}
|
713
|
+
|
714
|
+
void
|
715
|
+
P4ClientApi::Except( const char *func, const char *msg, const char *cmd )
|
716
|
+
{
|
717
|
+
StrBuf m;
|
718
|
+
|
719
|
+
m << msg;
|
720
|
+
m << "( " << cmd << " )";
|
721
|
+
Except( func, m.Text() );
|
722
|
+
}
|
723
|
+
|
724
|
+
void
|
725
|
+
P4ClientApi::Except( const char *func, Error *e )
|
726
|
+
{
|
727
|
+
StrBuf m;
|
728
|
+
|
729
|
+
e->Fmt( &m );
|
730
|
+
Except( func, m.Text() );
|
731
|
+
}
|
732
|
+
|