Skip to content
Newer
Older
100644 303 lines (250 sloc) 9.06 KB
5655d71 Refactoring:
Chris Thomas authored
1 //
2 // CommitWindowCommandLine.m
3 // CommitWindow
4 //
5 // Created by Chris Thomas on 6/24/06.
6 // Copyright 2006 Chris Thomas. All rights reserved.
7 //
8
9 #import "CommitWindowCommandLine.h"
10
7c0e6fd • There's now a visible diff button, as a first step toward status wi…
Chris Thomas authored
11 #import "NSTask+CXAdditions.h"
12
5655d71 Refactoring:
Chris Thomas authored
13 @implementation CommitWindowController(CommandLine)
14
15 - (void) awakeFromNib
16 {
17 NSProcessInfo * processInfo = [NSProcessInfo processInfo];
18 NSArray * args;
19 int i;
20 int argc;
21
22 args = [processInfo arguments];
23 argc = [args count];
24
25 if( args == nil || argc < 2 )
26 {
27 fprintf(stderr, "commit window: Arguments required\n");
28 [self cancel:nil];
29 }
30
31 //
32 // Parse the command line.
33 //
2917003 Implement CommitWindow per-item action menu.
Chris Thomas authored
34 // fDiffCommand and fActionCommands are set up according to the arguments given.
35 //
5655d71 Refactoring:
Chris Thomas authored
36
2917003 Implement CommitWindow per-item action menu.
Chris Thomas authored
37 // Program name is the first argument -- get rid of it.
5655d71 Refactoring:
Chris Thomas authored
38 argc -= 1;
39 args = [args subarrayWithRange:NSMakeRange(1, argc)];
40
41 // Populate our NSArrayController with the command line arguments
42 for( i = 0; i < argc; i += 1 )
43 {
44 NSString * argument = [args objectAtIndex:i];
45
46 if( [argument isEqualToString:@"--ask"] )
47 {
48 // Next argument should be the query text.
49 if( i >= (argc - 1) )
50 {
51 fprintf(stderr, "commit window: missing text: --ask \"some text\"\n");
52 [self cancel:nil];
53 }
54
55 i += 1;
56 argument = [args objectAtIndex:i];
57 [fRequestText setStringValue:argument];
58 }
dae08a0 @ciaran Adding a new option, --log, which takes a single string argument and …
ciaran authored
59 else if( [argument isEqualToString:@"--log"] )
60 {
61 // Next argument should be the initial log message text.
62 if( i >= (argc - 1) )
63 {
64 fprintf(stderr, "commit window: missing text: --log \"log message text\"\n");
65 [self cancel:nil];
66 }
67
68 i += 1;
69 argument = [args objectAtIndex:i];
70 [fCommitMessage setString:argument];
71 }
5655d71 Refactoring:
Chris Thomas authored
72 else if( [argument isEqualToString:@"--status"] )
73 {
74 // Next argument should be a colon-seperated list of status strings, one for each path
75 if( i >= (argc - 1) )
76 {
77 fprintf(stderr, "commit window: missing text: --status \"A:D:M:M:M\"\n");
78 [self cancel:nil];
79 }
80
81 i += 1;
82 argument = [args objectAtIndex:i];
83 fFileStatusStrings = [[argument componentsSeparatedByString:@":"] retain];
84 }
85 else if( [argument isEqualToString:@"--diff-cmd"] )
86 {
87 // Next argument should be a comma-seperated list of command arguments to use to execute the diff
88 if( i >= (argc - 1) )
89 {
90 fprintf(stderr, "commit window: missing text: --diff-cmd \"/usr/bin/svn,diff\"\n");
91 [self cancel:nil];
92 }
93
94 i += 1;
95 argument = [args objectAtIndex:i];
96 fDiffCommand = [argument retain];
97 }
2917003 Implement CommitWindow per-item action menu.
Chris Thomas authored
98 else if( [argument isEqualToString:@"--action-cmd"] )
99 {
100 //
101 // --action-cmd provides an action that may be performed on a file.
102 // Provide multiple action commands by passing --action-cmd multiple times, each with a different command argument.
103 //
104 // The argument to --action-cmd is two comma-seperated lists separated by a colon, of the form "A,M,D:Revert,/usr/local/bin/svn,revert"
105 //
106 // On the left side of the colon is a list of status character or character sequences; a file must have one of these
107 // for this command to be enabled.
108 //
109 // On the right side is a list:
110 // Item 1 is the human-readable name of the command.
111 // Item 2 is the path (either absolute or accessible via $PATH) to the executable.
112 // Items 3 through n are the arguments to the executable.
113 // CommitWindow will append the file path as the last argument before executing the command.
114 // Multiple paths may be appended in the future.
115 //
116 // The executable should return a single line of the form "<new status character(s)><whitespace><file path>" for each path.
117 //
118 // For Subversion, commands might be:
119 // "?:Add,/usr/local/bin/svn,add"
120 // "A:Mark Executable,/usr/local/bin/svn,propset,svn:executable,true"
121 // "A,M,D,C:Revert,/usr/local/bin/svn,revert"
122 // "C:Resolved,/usr/local/bin/svn,resolved"
123 //
124 // Only the first colon is significant, so that, for example, 'svn:executable' in the example above works as expected.
125 // This does scheme assume that neither comma nor colon will be used in status sequences. The file paths themselves may contain
126 // commas, since those are handled out of bounds. We could introduce comma or colon quoting if needed. But I hope not.
127 //
128 if( i >= (argc - 1) )
129 {
130 fprintf(stderr, "commit window: missing text: --action-cmd \"M,Revert,/usr/bin/svn,revert\"\n");
131 [self cancel:nil];
132 }
133
134 i += 1;
135 argument = [args objectAtIndex:i];
136
137 // Get status strings
138 NSString * statusSubstringString;
139 NSString * commandArgumentString;
140 NSArray * statusSubstrings;
141 NSArray * commandArguments;
142 NSRange range;
143
144 range = [argument rangeOfString:@":"];
145 if(range.location == NSNotFound)
146 {
147 fprintf(stderr, "commit window: missing ':' in --action-cmd\n");
148 [self cancel:nil];
149 }
150
151 statusSubstringString = [argument substringToIndex:range.location];
152 commandArgumentString = [argument substringFromIndex:NSMaxRange(range)];
153
154 statusSubstrings = [statusSubstringString componentsSeparatedByString:@","];
155 commandArguments = [commandArgumentString componentsSeparatedByString:@","];
156
157 unsigned int statusSubstringCount = [statusSubstrings count];
158
159 // Add the command to each substring
160 for(unsigned int index = 0; index < statusSubstringCount; index += 1)
161 {
162 NSString * statusSubstring = [statusSubstrings objectAtIndex:index];
163
164 [self addAction:[commandArguments objectAtIndex:0]
165 command:[commandArguments subarrayWithRange:NSMakeRange(1, [commandArguments count] - 1)]
166 forStatus:statusSubstring];
167 }
168 }
5655d71 Refactoring:
Chris Thomas authored
169 else
170 {
171 NSMutableDictionary * dictionary = [fFilesController newObject];
172
173 [dictionary setObject:[argument stringByAbbreviatingWithTildeInPath] forKey:@"path"];
174 [fFilesController addObject:dictionary];
175 }
176 }
177
178 //
179 // Done processing arguments, now add status to each item
180 // and choose default commit state
181 //
182 [self setupUserInterface];
183
184 }
185
186
187 #if 0
188 #pragma mark -
189 #pragma mark Actions
190 #endif
191
192
193
194 - (IBAction) commit:(id) sender
195 {
196 NSArray * objects = [fFilesController arrangedObjects];
197 int i;
198 int pathsToCommitCount = 0;
199 NSMutableString * commitString;
200
201 [self saveSummary];
202
203 //
204 // Quote any single-quotes in the commit message
205 // \' doesn't work with bash. We must use string concatenation.
206 // This sort of thing is why the Unix Hater's Handbook exists.
207 //
208 commitString = [[[fCommitMessage string] mutableCopy] autorelease];
209 [commitString replaceOccurrencesOfString:@"'" withString:@"'\"'\"'" options:0 range:NSMakeRange(0, [commitString length])];
210
211 fprintf(stdout, "-m '%s' ", [commitString UTF8String] );
212
213 //
214 // Return only the files we care about
215 //
216 for( i = 0; i < [objects count]; i += 1 )
217 {
218 NSMutableDictionary * dictionary;
219 NSNumber * commit;
220
221 dictionary = [objects objectAtIndex:i];
222 commit = [dictionary objectForKey:@"commit"];
223
224 if( commit == nil || [commit boolValue] ) // missing commit key defaults to true
225 {
226 NSMutableString * path;
227
228 //
229 // Quote any single-quotes in the path
230 //
231 path = [dictionary objectForKey:@"path"];
232 path = [[[path stringByStandardizingPath] mutableCopy] autorelease];
233 [path replaceOccurrencesOfString:@"'" withString:@"'\"'\"'" options:0 range:NSMakeRange(0, [path length])];
234
235 fprintf( stdout, "'%s' ", [path UTF8String] );
236 pathsToCommitCount += 1;
237 }
238 }
239
240 fprintf( stdout, "\n" );
241
242 //
243 // SVN will commit the current directory, recursively, if we don't specify files.
244 // So, to prevent surprises, if the user's unchecked all the boxes, let's be on the safe side and cancel.
245 //
246 if( pathsToCommitCount == 0 )
247 {
248 [self cancel:nil];
249 }
250
251 [NSApp terminate:self];
252 }
253
254 - (IBAction) cancel:(id) sender
255 {
256 [self saveSummary];
257
258 fprintf(stdout, "commit window: cancel\n");
259 exit(-128);
260 }
261
b61a83d • Get the absolute path to the diff command before launching it.
Chris Thomas authored
262
5655d71 Refactoring:
Chris Thomas authored
263 - (IBAction) doubleClickRowInTable:(id)sender
264 {
7c0e6fd • There's now a visible diff button, as a first step toward status wi…
Chris Thomas authored
265 if( fDiffCommand != nil )
5655d71 Refactoring:
Chris Thomas authored
266 {
b61a83d • Get the absolute path to the diff command before launching it.
Chris Thomas authored
267 static NSString * sCommandAbsolutePath = nil;
268
7c0e6fd • There's now a visible diff button, as a first step toward status wi…
Chris Thomas authored
269 NSMutableArray * arguments = [[fDiffCommand componentsSeparatedByString:@","] mutableCopy];
5200154 @sorbits • call stringByStandardizingPath on the paths before using them as ar…
sorbits authored
270 NSString * filePath = [[[[fFilesController arrangedObjects] objectAtIndex:[sender selectedRow]] objectForKey:@"path"] stringByStandardizingPath];
7c0e6fd • There's now a visible diff button, as a first step toward status wi…
Chris Thomas authored
271 NSData * diffData;
272 NSString * errorText;
273 int exitStatus;
b61a83d • Get the absolute path to the diff command before launching it.
Chris Thomas authored
274
275 // Resolve the command to an absolute path (only do this once per launch)
276 if(sCommandAbsolutePath == nil)
277 {
2917003 Implement CommitWindow per-item action menu.
Chris Thomas authored
278 sCommandAbsolutePath = [[self absolutePathForPath:[arguments objectAtIndex:0]] retain];
b61a83d • Get the absolute path to the diff command before launching it.
Chris Thomas authored
279 }
280 [arguments replaceObjectAtIndex:0 withObject:sCommandAbsolutePath];
281
282 // Run the diff
7c0e6fd • There's now a visible diff button, as a first step toward status wi…
Chris Thomas authored
283 [arguments addObject:filePath];
284 exitStatus = [NSTask executeTaskWithArguments:arguments
285 input:nil
286 outputData:&diffData
287 errorString:&errorText];
b61a83d • Get the absolute path to the diff command before launching it.
Chris Thomas authored
288 [self checkExitStatus:exitStatus forCommand:arguments errorText:errorText];
289
290 // Success, send the diff to TextMate
291 arguments = [NSArray arrayWithObjects:[NSString stringWithFormat:@"%s/bin/mate", getenv("TM_SUPPORT_PATH")], @"-a", nil];
5655d71 Refactoring:
Chris Thomas authored
292
b61a83d • Get the absolute path to the diff command before launching it.
Chris Thomas authored
293 exitStatus = [NSTask executeTaskWithArguments:arguments
294 input:diffData
295 outputData:nil
296 errorString:&errorText];
297 [self checkExitStatus:exitStatus forCommand:arguments errorText:errorText];
5655d71 Refactoring:
Chris Thomas authored
298 }
299 }
300
301
302 @end
Something went wrong with that request. Please try again.