/******************************************************************************* Copyright (c) 1997-2004, Perforce Software, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTR IBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *******************************************************************************/ /******************************************************************************* * Name : p4result.cc * * Author : Tony Smith <tony@perforce.com> or <tony@smee.org> * * Description : Ruby class for holding results of Perforce commands * ******************************************************************************/ #include <ruby.h> #include "undefdups.h" #include <clientapi.h> #include "gc_hack.h" #include "p4result.h" P4Result::P4Result() { output = rb_ary_new(); warnings = rb_ary_new(); errors = rb_ary_new(); } void P4Result::Reset() { output = rb_ary_new(); warnings = rb_ary_new(); errors = rb_ary_new(); } void P4Result::AddOutput( const char *msg ) { rb_ary_push( output, rb_str_new2( msg ) ); // // Call the ruby thread scheduler to allow another thread to run // now. We should perhaps only call this every 'n' times, but I've // no idea what a good value for n might be; so for now at least, n=1 // rb_thread_schedule(); } void P4Result::AddOutput( VALUE out ) { rb_ary_push( output, out ); // // Call the ruby thread scheduler to allow another thread to run // now. We should perhaps only call this every 'n' times, but I've // no idea what a good value for n might be; so for now at least, n=1 // rb_thread_schedule(); } void P4Result::AddError( Error *e ) { StrBuf m; e->Fmt( &m, EF_PLAIN ); int s; s = e->GetSeverity(); // // Empty and informational messages are pushed out as output as nothing // worthy of error handling has occurred. Warnings go into the warnings // list and the rest are lumped together as errors. // if ( s == E_EMPTY || s == E_INFO ) { AddOutput( m.Text() ); return; } if ( s == E_WARN ) rb_ary_push( warnings, rb_str_new2( m.Text() ) ); else rb_ary_push( errors, rb_str_new2( m.Text() ) ); // // Call the ruby thread scheduler to allow another thread to run // now. We should perhaps only call this every 'n' times, but I've // no idea what a good value for n might be; so for now at least, n=1 // rb_thread_schedule(); } int P4Result::ErrorCount() { return Length( errors ); } int P4Result::WarningCount() { return Length( warnings ); } void P4Result::FmtErrors( StrBuf &buf ) { Fmt( "[Error]: ", errors, buf ); } void P4Result::FmtWarnings( StrBuf &buf ) { Fmt( "[Warning]: ", warnings, buf ); } int P4Result::Length( VALUE ary ) { ID iLength; VALUE len; iLength = rb_intern( "length" ); len = rb_funcall( ary, iLength, 0 ); return NUM2INT( len ); } void P4Result::GCMark() { rb_gc_mark( output ); rb_gc_mark( errors ); rb_gc_mark( warnings ); } void P4Result::Fmt( const char *label, VALUE ary, StrBuf &buf ) { ID idJoin; VALUE s1; StrBuf csep; VALUE rsep; buf.Clear(); // If the array is empty, then we just return if( ! Length( ary ) ) return; // Not empty, so we'll format it. idJoin = rb_intern( "join" ); // This is the string we'll use to prefix each entry in the array csep << "\n\t" << label; rsep = rb_str_new2( csep.Text() ); // Since Array#join() won't prefix the first element with the separator // we'll have to do it manually. buf << csep; // Join the array elements together, and append the result to the buffer s1 = rb_funcall( ary, idJoin, 1, rsep ); buf << STR2CSTR( s1 ); return; }
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#5 | 5693 | Tony Smith |
Update p4conf.rb to define const_char on all platforms if building against a 2006.1 or later API. Also squelched some compiler noise. No functional change |
||
#4 | 5105 | Tony Smith |
Make P4Ruby include the text of any errors or warnings in exception messages. Previously the user had to call P4#errors() and/or P4#warnings() to display this information and if you didn't handle P4Exception specifically the message could look somewhat cryptic. This change hopefully makes it easier - particularly for newbies. Note that the text of warnings is not shown unless you're using exception level 2 (P4::RAISE_ALL). |
||
#3 | 4587 | Tony Smith |
Support for multi-threaded use of P4Ruby. Previously, whilst you could create a multithreaded application and use P4 objects in different threads, all P4#run() method calls were serialised so there was no gain. This was because Ruby's threading model is co-operative and P4Ruby wasn't co-operating. With this change, we now call rb_thread_schedule() so multithreading works as expected. There may still be some problems with termination if an exception is raised in another thread at an inopportune moment but so far it's handled all the tests I've thrown at it. |
||
#2 | 4157 | Tony Smith |
Copyright notice update. No functional change |
||
#1 | 1750 | Tony Smith | Build environment tweaks. | ||
//guest/tony_smith/perforce/API/Ruby/main/p4result.cc | |||||
#3 | 1391 | Tony Smith |
Bug fix. Garbage collection can apparently run at any time (i.e. when you're in C space and not just when you're in Ruby space) and it was occasionally running in between adjacent "delete" and "new" statements when the result set was being reset. This change removes this race condition by making the result member of ClientUserRuby a permanently instantiated variable and extending the P4Result class so that it can reset itself in a way that GC respects. Now the only dynamically allocated C++ object is the top level P4ClientApi object. No functional change. |
||
#2 | 1166 | Tony Smith |
Followup to previous change. Simplify the interface to getting results/errors and warnings. No need for the P4Result class anymore so that's gone (though it's still there as a C++ class because it's useful) and so is P4#result. Now you get your errors/warnings and results using P4#errors, P4#warnings and P4#output all of which return arrays. |
||
#1 | 1164 | Tony Smith |
Reworked exception handling (hopefully for the last time) in P4/Ruby. Now exceptions are raised on completion of Perforce commands if any errors or warnings were received as part of executing the command. This change also adds documentation, and indexes the Ruby interface off my main page. Bad form to combine so many changes in one changelist, but it's getting late and I want to get them submitted! |