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
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
|
+
|
data/ext/P4/undefdups.h
ADDED
@@ -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
|