source: users/rhwood/Pallet/PortAuthority.m @ 28253

Last change on this file since 28253 was 28253, checked in by rhwood@…, 13 years ago

Add the MPAgent (PalletHelper) calls and delegate methods.

File size: 29.4 KB
Line 
1/*
2        Class MPAuthority
3        Project Pallet
4 
5        Copyright (C) 2006 MacPorts.
6 
7        This code is free software; you can redistribute it and/or modify it under
8        the terms of the GNU General Public License as published by the Free
9        Software Foundation; either version 2 of the License, or any later version.
10 
11        This code is distributed in the hope that it will be useful, but WITHOUT ANY
12        WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13        FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14        details.
15 
16        For a copy of the GNU General Public License, visit <http://www.gnu.org/> or
17        write to the Free Software Foundation, Inc., 59 Temple Place--Suite 330,
18        Boston, MA 02111-1307, USA.
19 
20        More information is available at http://www.macports.org or macports-users@lists.macosforge.org
21 
22        History:
23       
24        Created by Randall Wood rhwood@macports.org on 6 October 2006
25 */
26
27#import "PortAuthority.h"
28
29#include <tcl.h>
30
31@implementation PortAuthority
32
33enum portCommands {
34        portInstall,
35        portList,
36        portListAll,
37        portSync,
38        portSelfupdate,
39        portListInstalled,
40        portListOutdated
41};
42
43#pragma mark STARTUP
44
45- (void)awakeFromNib
46{
47        // Get a MacPorts Interpeter
48        interpeter = [[MPInterp alloc] init];
49        if (![interpeter loadPackage:MPPackageName version:MPPackageVersion usingCommand:MPPackageInit]) {
50                NSLog(@"Failed to load interpeter");
51                exit(1);
52        }
53        if (![interpeter redirectCommand:MPUIPuts toObject:self]) {
54                NSLog(@"Failed to redirect interpeter input");
55                exit(1);
56        }
57        NSLog(@"Printing system_options");
58        NSLog([[interpeter getVariable:[MPObject objectWithString:@"system_options"]] stringValue]);
59        NSLog(@"system_options printed");
60        // Load/set preferences/defaults
61        if (![[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"portInstallationPath"]) {
62                [[[NSUserDefaultsController sharedUserDefaultsController] values] setValue:@"/opt/local" forKey:@"portInstallationPath"];
63                NSString *userDefaultsValuesPath;
64                NSDictionary *userDefaultsValuesDict;
65                userDefaultsValuesPath = [[NSBundle mainBundle] pathForResource:@"UserDefaults"
66                                                                                                                                 ofType:@"plist"];
67                userDefaultsValuesDict = [NSDictionary dictionaryWithContentsOfFile:userDefaultsValuesPath];
68                [[NSUserDefaults standardUserDefaults] registerDefaults:userDefaultsValuesDict];
69                [[NSUserDefaultsController sharedUserDefaultsController] setInitialValues:userDefaultsValuesDict];
70        }
71        // Hide duplicate items in Windows menu
72        [portsWindow setExcludedFromWindowsMenu:YES];
73        [portLogWindow setExcludedFromWindowsMenu:YES];
74        // Locate port
75        macPortsPath = [[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"portInstallationPath"];
76        macPortsPort = [[NSString alloc] initWithString:[macPortsPath stringByAppendingPathComponent:@"bin/port"]];
77        // Initialize the port settings cache
78        portSettings = [[NSMutableDictionary alloc] init];
79        // Clean the main window
80        [status setStringValue:@""];
81        // Setup the port task
82        portIsRunning = NO;
83        launcher = [[NSBundle mainBundle] pathForResource:@"Launcher" ofType:nil];
84        agentTask = [[AuthorizedExecutable alloc] initWithExecutable:launcher];
85        authPortTask = [[AuthorizedExecutable alloc] initWithExecutable:launcher];
86        killTask = [[AuthorizedExecutable alloc] initWithExecutable:launcher];
87        [agentTask setDelegate:self];
88        [authPortTask setDelegate:self];
89        [killTask setDelegate:self];
90        // Setup the value transformers used in bindings
91        NSValueTransformer *transformer = [[PAStatusTransformer alloc] init];
92        [NSValueTransformer setValueTransformer:transformer forName:@"PAStatusTransformer"];
93        // UI Tweaks
94        [[portsList headerView] setMenu:portsListHeaderMenu];
95        [[portsList cornerView] setMenu:portsListHeaderMenu];
96        // TESTING TESTING TESTING
97        NSLog(@"Ports Database path: %@", [self configurationSetting:@"portdbpath"]);
98}
99
100/*
101        TODO: rewrite to run sync/selfupdate, and port list methods in thread so as not to block UI.
102 */
103- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
104{
105        // configure and register the connection to the PalletHelper
106        connection = [NSConnection defaultConnection];
107    [connection setRootObject: self];
108    [connection enableMultipleThreads];
109    if ([connection registerName:MPAppMessagePort] == NO) {
110        NSRunAlertPanel(@"Pallet", @"Could not register Pallet connection on this host.", nil, @"Quit", nil);
111        [NSApp terminate: self];
112    }
113       
114        // sync or selfupdate as required
115        if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"updateMacPortsOnStartup"] boolValue] == YES) {
116                [self updateMacPorts:nil];
117        } else if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"synchronizePortsListOnStartup"] boolValue] == YES) {
118                [self syncPortsList:nil];
119        }
120        // List ports   
121        [self getPortIndexes];
122        [self populatePortIndex];
123}
124
125#pragma mark PORT INDEX
126
127- (NSDictionary *)tPorts
128{
129        if (!_ports) {
130                NSPropertyListFormat format;
131                NSString *error;
132                NSData *portsData = [[self agent] portsData];
133                _ports= [[NSPropertyListSerialization propertyListFromData:portsData
134                                                                                                  mutabilityOption:NSPropertyListMutableContainersAndLeaves
135                                                                                                                        format:&format
136                                                                                                  errorDescription:&error]
137                        retain];
138        }
139        NSLog(_ports);
140        return _ports;
141}
142
143- (void)getPortIndexes
144{
145        NSArray *conf;
146        NSString *path;
147        NSString *file;
148        NSMutableDictionary *sources;
149        NSEnumerator *enumerator;
150        id line;
151        NSMutableString *source;
152
153        source = [[NSMutableString alloc] init];
154        sources = [[NSMutableDictionary alloc] init];
155        path = [macPortsPath stringByAppendingPathComponent:@"etc/macports/sources.conf"];
156        file = [[NSString alloc] initWithContentsOfFile:path];
157        conf = [[NSArray alloc] initWithArray:[file componentsSeparatedByString:@"\n"]];
158        if ([conf count] == 1) {
159                [conf release];
160                conf = [[NSArray alloc] initWithArray:[file componentsSeparatedByString:@"\r"]];
161        }
162        enumerator = [conf objectEnumerator];
163        while (line = [enumerator nextObject]) {
164                @try {
165                        if ([line characterAtIndex:0] != '#') {
166                                [sources setValue:[self pathToPortIndexWithSource:line] forKey:line];
167                        }
168                }
169                @catch (NSException *exception) {
170                        // Exceptions will be thrown where line is nil or 0 length
171                        // Ignore the exception since it means only that the line was empty
172                }
173        }
174        if (portIndexes != nil) {
175                [portIndexes release];
176        }
177        portIndexes = [[NSDictionary alloc] initWithDictionary:sources copyItems:YES];
178}
179
180- (NSString *)pathToPortIndexWithSource:(NSString *)source
181{
182        NSMutableString *path;
183        NSRange range;
184        path = [[NSMutableString alloc] init];
185        range = [source rangeOfString:@"://"];
186        [path setString:[source substringFromIndex:(range.location + range.length)]];
187        // if the source URL is not a file:// type URL, prepend it with ${prefix}/var/macports/sources
188        if (![[source substringToIndex:4] isEqualToString:@"file"]) {
189                [path setString:[[macPortsPath stringByAppendingPathComponent:@"var/macports/sources"] stringByAppendingPathComponent:path]];
190        }
191        return [path stringByAppendingPathComponent:@"PortIndex"];
192}
193
194- (void)parsePortIndex:(NSString *)index intoIndexObject:(id)indexObject
195{
196        NSString *file;
197        NSArray *lines;
198        NSMutableArray *arrays;
199        NSMutableDictionary *port;
200        NSArray *array;
201        NSEnumerator *indexEnumerator;
202        int counter;
203        int tclCount;
204        int tclResult;
205        const char **tclElements;
206        NSStringEncoding encoding;
207        NSString *key;
208        id value;
209        NSMutableArray *values;
210        NSEnumerator *valuesEnumerator;
211        int valuesCount;
212        int valuesCounter;
213        const char **valuesElements;
214        id line;
215        arrays = [[NSMutableArray alloc] init];
216        file = [[NSString alloc] initWithContentsOfFile:index];
217        lines = [file componentsSeparatedByString:@"\n"];
218        indexEnumerator = [lines objectEnumerator];
219        // throw away the lines that contain only two words (the portname and a number)
220        while (line = [indexEnumerator nextObject]) {
221                array = [line componentsSeparatedByString:@" "];
222                if ([array count] > 2) {
223                        [arrays addObject:line];
224                }
225        }
226        indexEnumerator = [arrays objectEnumerator];
227        encoding = [NSString defaultCStringEncoding];
228        while (line = [indexEnumerator nextObject]) {
229                port = [[NSMutableDictionary alloc] init];
230                tclResult = Tcl_SplitList(NULL, [line cString], &tclCount, &tclElements);
231                if (tclResult == TCL_OK && !(tclCount % 2)) {
232                        for (counter = 0; counter < tclCount; counter+=2) {
233                                key = [[NSString alloc] initWithCString:tclElements[counter] encoding:encoding];
234                                if ([key isEqualToString:@"maintainers"] ||
235                                        [key isEqualToString:@"depends_lib"] ||
236                                        [key isEqualToString:@"categories"]     ||
237                                        [key isEqualToString:@"depends_build"]) {
238                                        tclResult = Tcl_SplitList(NULL, tclElements[counter + 1], &valuesCount, &valuesElements);
239                                        if (tclResult == TCL_OK) {
240                                                values = [[NSMutableArray alloc] initWithCapacity:valuesCount];
241                                                for (valuesCounter = 0; valuesCounter < valuesCount; valuesCounter++) {
242                                                        [values addObject:[[NSString alloc] initWithCString:valuesElements[valuesCounter] encoding:encoding]];
243                                                }
244                                        } else {
245                                                values = [[NSArray alloc] init];
246                                        }
247                                        value = [[NSArray alloc] initWithArray:values];
248                                        // create a string containing all the tokens so that it can be rapidly and easily searched
249                                        [port setValue:[[NSString alloc] initWithCString:tclElements[counter + 1] encoding:encoding] forKey:[key stringByAppendingString:@"_as_string"]];
250                                } else {
251                                        value = [[NSString alloc] initWithCString:tclElements[counter + 1] encoding:encoding];
252                                }
253                                [port setValue:value forKey:key];
254                                //NSLog(@"%@: %@\n", key, value);
255                        }
256                        if ([port valueForKey:@"depends_lib"]) {
257                                values = [[NSMutableArray alloc] initWithArray:[port valueForKey:@"depends_lib"]];
258                                valuesCount = [values count];
259                                for (valuesCounter = 0; valuesCounter < valuesCount; valuesCounter++) {
260                                        value = [[[values objectAtIndex:valuesCounter] componentsSeparatedByString:@":"] lastObject];
261                                        [values replaceObjectAtIndex:valuesCounter withObject:value];
262                                }
263                                [port setValue:[[NSArray alloc] initWithArray:values] forKey:@"depends_lib"];
264                        }
265                        if ([port valueForKey:@"depends_build"]) {
266                                values = [[NSMutableArray alloc] initWithArray:[port valueForKey:@"depends_build"]];
267                                valuesCount = [values count];
268                                for (valuesCounter = 0; valuesCounter < valuesCount; valuesCounter++) {
269                                        value = [[[values objectAtIndex:valuesCounter] componentsSeparatedByString:@":"] lastObject];
270                                        [values replaceObjectAtIndex:valuesCounter withObject:value];
271                                }
272                                [port setValue:[[NSArray alloc] initWithArray:values] forKey:@"depends_build"];
273                        }
274                        @try {
275                                if ([[port valueForKey:@"long_description"] characterAtIndex:0] == '{') {
276                                        [port setValue:[port valueForKey:@"description"] forKey:@"long_description"];
277                                }
278                        }
279                        @catch (NSException *e) {
280                                [port setValue:[NSString stringWithFormat:
281                                        NSLocalizedStringWithDefaultValue(@"parsePortIndexDescreiptionError",
282                                                                                                          @"Localizable",
283                                                                                                          [NSBundle mainBundle],
284                                                                                                          @"Port has an invalid desciption or long_description key.",
285                                                                                                          @"Error statement for exception raised when testing long_description.")]
286                                                forKey:@"long_description"];
287                        }
288                        // generate a composite version string: version_revision
289                        [port setValue:[[[port valueForKey:@"version"] stringByAppendingString:@"_"] stringByAppendingString:[port valueForKey:@"revision"]] forKey:@"compositeVersion"];
290                        // set the status flag to unknown
291                        [port setValue:[NSNumber numberWithInt:portStatusUnknown] forKey:@"status"];
292                        [indexObject addObject:port];
293                } else {
294                        NSLog(@"Line \"%@\" from index %@ is bad.\n", line, index);
295                }
296        }
297        //NSLog(@"Parsed %d ports from index %@\n", [ports count], index);
298        Tcl_Free((char *)tclElements);
299}
300
301- (void)populatePortIndex
302{
303        NSEnumerator *indexEnumerator;
304        id index;
305        if (portIndex = nil) {
306                portIndex = [[NSMutableArray alloc] init];
307        }
308        indexEnumerator = [portIndexes keyEnumerator];
309        while (index = [indexEnumerator nextObject]) {
310                [progressIndicator startAnimation:nil];
311                [status setStringValue:@"Listing ports in all indexes..."];
312                [status setStringValue:[NSString stringWithFormat:
313                        NSLocalizedStringWithDefaultValue(@"statusPopulatePortIndex",
314                                                                                          @"Localizable",
315                                                                                          [NSBundle mainBundle],
316                                                                                          @"Listing ports in index %@",
317                                                                                          @"Status for [MPAuthority populatePortIndex] method"),
318                        index]];
319                [self parsePortIndex:[portIndexes valueForKey:index] intoIndexObject:portIndexController];
320        }
321        [status setStringValue:@""];
322        [progressIndicator stopAnimation:nil];
323}
324
325- (void)indexPortsInThread
326{
327       
328}
329
330#pragma mark PORT CONFIGURATION
331
332- (NSString *)configurationSetting:(NSString *)setting
333/*
334 For some reason, the below script can not find {$prefix}/etc/ports/ports.conf
335 So what we need to do is execute a tclsh resource script to get conf settings out of port
336 
337 Better yet, create a RFE for port to dump its configuration settings so we can read all port conf files
338 without knowing where the setting came from (default, ports.conf, .portrc, wherever)...
339 */
340{
341        if ([portSettings valueForKey:setting] == nil) {
342                int tclResult;
343                Tcl_Interp *tcl;
344                NSString *script = [[NSString alloc] initWithFormat:@"source %@/etc/macports/macports.conf\nproc %@ x {puts [list %2$@ $x]}", macPortsPath, setting, nil];
345                NSLog(script);
346                tcl = Tcl_CreateInterp();
347                tclResult = Tcl_EvalEx(tcl, [script cString], -1, TCL_EVAL_GLOBAL);
348                if (tclResult == TCL_OK) {
349                        NSLog(@"%s", Tcl_GetStringResult(tcl));
350                        [portSettings setValue:[NSString stringWithCString:Tcl_GetStringResult(tcl)] forKey:setting];
351                } else {
352                        NSLog(@"%s", Tcl_ErrnoMsg(Tcl_ErrnoId()));
353                }
354                Tcl_DeleteInterp(tcl);
355        }
356        return [portSettings valueForKey:setting];
357}
358
359#pragma mark PORT COMMANDS
360
361- (void)defaultAction:(id)items
362/*
363 rewrite to use other methods in this class to avoid duplication
364 */
365{
366        id item;
367        switch ([[item valueForKey:@"status"] intValue]) {
368                case portStatusActive:
369                        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
370                                @"uninstall",
371                                @"-dv",
372                                [item valueForKey:@"name"]]];
373                        break;
374                case portStatusInstalled:
375                        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
376                                @"activate",
377                                @"-dv",
378                                [item valueForKey:@"name"]]];
379                        break;
380                case portStatusOutdated:
381                        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
382                                @"upgrade",
383                                @"-dv",
384                                [item valueForKey:@"name"]]];
385                        break;
386                case portStatusUnknown:
387                        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
388                                @"install",
389                                @"-dv",
390                                [item valueForKey:@"name"]]];
391                        break;
392                default:
393                        break;
394        }
395}
396
397- (IBAction)installPort:(id)sender
398{
399        portCommand = portInstall;
400        NSArray *selection = [portIndexController selectedObjects];
401        NSEnumerator *selectionEnumerator = [selection objectEnumerator];
402        id port;
403        while (port = [selectionEnumerator nextObject]) {
404                [self installSinglePort:[port objectForKey:@"name"]];
405        }
406}
407
408- (void)installSinglePort:(NSString *)port
409{
410        [status setStringValue:[NSString localizedStringWithFormat:NSLocalizedStringWithDefaultValue(@"statusInstallPort",
411                                                                                                                         @"Localizable",
412                                                                                                                         [NSBundle mainBundle],
413                                                                                                                         @"Preparing to install %@",
414                                                                                                                         @"Status for [MPAuthority installPort] method"),
415                port]];
416        NSLog([status stringValue]);
417        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
418                @"-dv",
419                @"install",
420                port,
421                nil]];
422}
423
424- (IBAction)reinstallPort:(id)sender
425{
426}
427
428- (IBAction)removePort:(id)sender
429{
430}
431
432- (IBAction)syncPortsList:(id)sender
433{
434        portCommand = portSync;
435        [status setStringValue:NSLocalizedStringWithDefaultValue(@"statusSyncPortsList",
436                                                                                                                         @"Localizable",
437                                                                                                                         [NSBundle mainBundle],
438                                                                                                                         @"Syncing ports list with MacPorts",
439                                                                                                                         @"Status for [MPAuthority syncPortsList] method")];
440        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
441                @"sync",
442                @"-dv",
443                nil]];
444}
445
446- (IBAction)updateMacPorts:(id)sender
447{
448        portCommand = portSelfupdate;
449        [status setStringValue:NSLocalizedStringWithDefaultValue(@"statusUpdateMacPorts",
450                                                                                                                         @"Localizable",
451                                                                                                                         [NSBundle mainBundle],
452                                                                                                                         @"Updating MacPorts Installation",
453                                                                                                                         @"Status for [MPAuthority updateMacPorts] method")];
454        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
455                @"selfupdate",
456                nil]];
457}
458
459- (IBAction)upgradeOutdated:(id)sender
460{
461        NSLog(@"Upgrade Outdated\n");
462        portCommand = portSelfupdate;
463        [status setStringValue:NSLocalizedStringWithDefaultValue(@"statusUpgradeOutdated",
464                                                                                                                         @"Localizable",
465                                                                                                                         [NSBundle mainBundle],
466                                                                                                                         @"Preparing to upgrade all outdated ports...",
467                                                                                                                         @"Status for [MPAuthority upgradeOutdated] method")];
468        [self launchAuthorizedExecutableWithArguments:[NSArray arrayWithObjects:macPortsPort,
469                @"-dv",
470                @"upgrade",
471                @"outdated",
472                nil]];
473}
474
475- (IBAction)upgradePort:(id)sender
476{
477}
478
479- (IBAction)haltPortCommand:(id)sender
480{
481       
482}
483
484- (void)runPortCommand:(NSString *)action port:(NSString *)port
485{
486       
487}
488
489
490
491- (void)runPortCommandInThread:(id)parameters
492{
493       
494}
495
496#pragma mark TABLES
497
498- (void)updateAvailablePorts:(id)output
499{
500        NSMutableArray *fields;
501        NSMutableDictionary *columns;
502        columns = [[NSMutableDictionary alloc] initWithCapacity:4];
503        fields = [[NSMutableArray alloc] initWithArray:[output componentsSeparatedByString:@" "]];
504        [fields removeObjectIdenticalTo:[NSString string]];
505        [columns setValue:[NSNumber numberWithInt:portStatusUnknown] forKey:@"status"];
506        [columns setValue:[fields objectAtIndex:0] forKey:@"name"];
507        [columns setValue:[fields objectAtIndex:1] forKey:@"version"];
508        [columns setValue:[fields objectAtIndex:2] forKey:@"categories"];
509        [portIndex addObject:columns];
510        [portsList reloadData];
511}
512
513#pragma mark TABLE DATASOURCES
514
515- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
516{
517        NSLog(@"request for row %@ column %@\n", [NSNumber numberWithInt:rowIndex], [aTableColumn identifier]);
518        NSParameterAssert(rowIndex >= 0 && rowIndex < [portIndex count]);
519        if ([[[aTableColumn identifier] stringValue] isEqualToString:@"status"]) {
520                switch ([[[portIndex objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]] intValue]) {
521                        case portStatusInstalled:
522                                return nil;
523                                break;
524                        case portStatusActive:
525                                return nil;
526                                break;
527                        case portStatusOutdated:
528                                return nil;
529                                break;
530                        default:
531                                return nil;
532                }
533        }
534        return [[portIndex objectAtIndex:rowIndex] objectForKey:[aTableColumn identifier]];
535}
536
537- (int)numberOfRowsInTableView:(NSTableView *)aTableView
538{
539        return [portIndex count];
540}
541
542#pragma mark MENU ITEMS
543
544- (IBAction)about:(id)sender
545{
546        NSMutableDictionary *options;
547        NSMutableAttributedString *credits;
548        NSMutableString *version;
549       
550        version = [NSMutableString stringWithContentsOfFile:[macPortsPath stringByAppendingPathComponent:@"etc/ports/dp_version"]];
551        [version deleteCharactersInRange:NSMakeRange([version length] - 1, 1)];
552        credits = [[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:
553                NSLocalizedStringFromTable(@"MacPorts Version: %@",
554                                                                   @"Localizable",
555                                                                   @"MacPorts Version"),
556                version]];
557       
558        [credits setAlignment:NSCenterTextAlignment range:NSMakeRange(0, [credits length])];
559        [credits addAttribute:@"NSFontAttributeName" value:[NSFont labelFontOfSize:[NSFont labelFontSize]] range:NSMakeRange(0, [credits length])];
560        options = [[NSMutableDictionary alloc] init];
561        [options setObject:credits forKey:@"Credits"];
562        [NSApp orderFrontStandardAboutPanelWithOptions:options];
563}
564
565- (IBAction)macPortsSite:(id)sender
566{
567        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.macports.org"]];
568}
569
570- (IBAction)portAuthoritySite:(id)sender
571{
572        [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.macports.org"]];
573}
574
575#pragma mark UTILITIES
576
577- (void)launchExecutableWithArguments:(NSMutableArray *)args
578{
579        if (!portIsRunning) {
580                portIsRunning = YES;
581                [NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIconBusy"]];
582                if (portTask != nil) {
583                        [portTask release];
584                }
585                portTask = [[TaskWrapper alloc] initWithController:self arguments:args];
586                [portTask startProcess];
587        }
588}
589
590- (void)launchAuthorizedExecutableWithArguments:(NSMutableArray *)args
591{
592        NSLog(@"Launching command %@", args);
593        if (!portIsRunning) {
594                portIsRunning = YES;
595                [NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIconBusy"]];
596                [authPortTask setArguments:args];
597                [authPortTask authorizeWithQuery];
598                [progressIndicator startAnimation:nil];
599                [authPortTask start];
600        } else {
601                [taskQueue addObject:args];
602        }
603}
604
605#pragma mark TOOLBAR
606
607- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
608{
609        return YES;
610}
611
612#pragma mark MACPORTS INTERPETER
613
614- (NSDictionary *)listPorts:(NSString *)query
615{   
616    Tcl_Obj **objv;
617    int count = 0, i=0;
618    MPObject *result;
619    NSString *error;
620    NSMutableDictionary *portsData;
621
622        //    [_ports removeAllObjects];
623    result = [interpeter evaluateCommand:[MPObject objectWithString:MPSearchCommand]
624                                                          withObject:[MPObject objectWithString:query]];
625    Tcl_ListObjGetElements(NULL, [result tclObj], &count, &objv);       
626    while (++i < count) {       
627        NSMutableDictionary *portDict = [NSMutableDictionary dictionary];
628        Tcl_Obj **innerobjs;
629        int innercount = 0, j = 0;   
630        Tcl_ListObjGetElements(NULL, objv[i++], &innercount, &innerobjs);
631        while (j < innercount)
632        {
633            MPObject *keyObject = [MPObject objectWithTclObj: innerobjs[j++]];
634            MPObject *valueObject = [MPObject objectWithTclObj: innerobjs[j++]];
635            NSString *key = [keyObject stringValue];
636            id value;
637            if ([key isEqualToString: MPCategoriesKey] || [key isEqualToString: MPMaintainersKey]) {
638                NSEnumerator *enm = [[[valueObject stringValue] componentsSeparatedByString: @" "] objectEnumerator];
639                NSString *component;
640                value = [NSMutableArray array];
641                while (component = [enm nextObject]) {
642                    if (![value containsObject: component]) {
643                        [value addObject: component];
644                    }
645                }
646            } else if ([key rangeOfString: MPDependsKey].location != NSNotFound) {
647                NSEnumerator *dependencyEnm = [[[valueObject stringValue] componentsSeparatedByString: @" "] objectEnumerator];
648                NSString *component;
649                value = [NSMutableArray array];
650                while (component = [dependencyEnm nextObject]) {
651                    NSString *dependencyName = [[component componentsSeparatedByString: @":"] objectAtIndex: 2];
652                    if (![value containsObject: dependencyName]) {
653                        [value addObject: dependencyName];
654                    }
655                }
656                key = MPDependsKey;
657            } else {
658                value = [valueObject stringValue];
659            }
660            [portDict setObject:value forKey:key];
661        }
662        [portsData setObject:portDict forKey:[portDict objectForKey:MPNameKey]];
663    }
664    return [NSDictionary dictionaryWithDictionary:portsData];
665}
666
667- (MPObject *) ui_puts: (NSArray *)array
668{
669    NSDictionary *message = [[array objectAtIndex: 1] dictionaryValue];
670    if (message == nil)
671        return [MPObject objectWithString: MPNoResult];
672       
673    NSString *data = [message objectForKey: @"data"];
674    NSString *priority = [message objectForKey: @"priority"];
675    if (data == nil || priority == nil)
676        return [MPObject objectWithString: MPNoResult];
677       
678    id delegate = [[[NSThread currentThread] threadDictionary] objectForKey: @"delegate"];
679    //[delegate displayMessage: message forPortName: [_currentOp objectForKey: @"portName"]];
680    return [MPObject objectWithString: MPYesResult];
681}
682
683#pragma mark MACPORTS AGENT
684
685- (id <MPAgentProtocol>)agent {
686        if (agentIsBusy) {
687                return nil;
688        }
689        agentIsBusy = YES;
690        if (!agent) {
691                NSString *agentPath = [[NSBundle mainBundle] pathForResource:@"PalletHelper" ofType:@""];
692                int i;
693//              [self launchAuthorizedExecutableWithArguments:];
694                [agentTask setArguments:[NSArray arrayWithObjects:agentPath, nil]];
695                [agentTask authorizeWithQuery];
696                [agentTask start];
697                for (i = 0; i < 10; i++) {
698                        connection = [[NSConnection connectionWithRegisteredName:MPAgentMessagePort host:nil] retain];
699                        if (connection) {
700                                break;
701                        }
702                        sleep(1);
703                }
704                if (!connection) {
705                        NSRunAlertPanel(@"Pallet", @"Could not connect to PalletHelper.", nil, nil, nil);
706                        // exit(0); don't exit as I want to see the bloody console window
707                }
708                agent = [[connection rootProxy] retain];
709                [(NSDistantObject *)agent setProtocolForProxy:@protocol(MPAgentProtocol)];
710                [connection setRootObject:self];
711                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionDidDie:) name:NSConnectionDidDieNotification object:connectionInvalid];
712        }
713        agentIsBusy = NO;
714        return agent;
715}
716
717- (void)connectionDidDie:(id)server
718{
719    NSRunAlertPanel(@"Pallet", @"Connection to PalletHelper died!", nil, nil, nil);
720    agent = nil;
721    // resetting agent to nil will cause a new instance of the agent to
722    // be spawned by [PortAuthority agent] next time someone tries to access it
723}
724
725- (oneway void)displayMessage:(in bycopy NSDictionary *)message forPortName:(in bycopy NSString *)portName {
726        [self appendOutput:[message objectForKey:@"data"]];
727}
728
729- (void)executeTarget:(NSString *)target forPortName:(NSString *)portName {
730        NSDictionary *operation = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
731                portName, @"portName",
732                target, "@target",
733                nil];
734        if (!operations) {
735                operations = [[NSMutableArray alloc] init];
736        }
737        [operations addObject:operation];
738        [[self agent] executeTarget:target forPortName:portName];
739}
740
741- (BOOL)shouldPerformTarget:(in bycopy NSString *)target forPortName:(in bycopy NSString *)portName {
742        return YES;
743}
744
745- (oneway void)willPerformTarget:(in bycopy NSString *)target forPortName:(in bycopy NSString *)portName {
746        [progressIndicator startAnimation:nil];
747        [NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIconBusy"]];
748}
749
750- (oneway void)didPerformTarget:(in bycopy NSString *)target forPortName:(in bycopy NSString *)portName withResult:(in bycopy NSString *)result {
751        [progressIndicator stopAnimation:nil];
752        [NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIcon"]];
753        [status setStringValue:@""];
754}
755
756#pragma mark AUTHORIZED EXECUTABLE DELEGATES / TASK WRAPPER CONTROLLER
757// This callback is implemented as part of conforming to the ProcessController protocol.
758// It will be called whenever there is output from the TaskWrapper.
759- (void)appendOutput:(NSString *)output
760{
761    // add the string (a chunk of the results from locate) to the NSTextView's
762    // backing store, in the form of an attributed string
763    [[portLog textStorage] appendAttributedString: [[[NSAttributedString alloc]
764                             initWithString: output] autorelease]];
765    // setup a selector to be called the next time through the event loop to scroll
766    // the view to the just pasted text.  We don't want to scroll right now,
767    // because of a bug in Mac OS X version 10.1 that causes scrolling in the context
768    // of a text storage update to starve the app of events
769    [self performSelector:@selector(scrollToVisible:) withObject:nil afterDelay:0.0];
770        switch (portCommand) {
771        }
772}
773
774// This routine is called after adding new results to the text view's backing store.
775// We now need to scroll the NSScrollView in which the NSTextView sits to the part
776// that we just added at the end
777- (void)scrollToVisible:(id)ignore {
778    [portLog scrollRangeToVisible:NSMakeRange([[portLog string] length], 0)];
779}
780
781// A callback that gets called when a TaskWrapper is launched, allowing us to do any setup
782// that is needed from the app side.  This method is implemented as a part of conforming
783// to the ProcessController protocol.
784- (void)processStarted
785{
786    portIsRunning = YES;
787    [portLog setString:@""];
788        [progressIndicator startAnimation:nil];
789}
790
791// A callback that gets called when a TaskWrapper is completed, allowing us to do any cleanup
792// that is needed from the app side.  This method is implemented as a part of conforming
793// to the ProcessController protocol.
794- (void)processFinished
795{
796    portIsRunning = NO;
797        [status setStringValue:@""];
798        [progressIndicator stopAnimation:nil];
799        if ([taskQueue count]) {
800                [self launchAuthorizedExecutableWithArguments:[taskQueue objectAtIndex:0]];
801                [taskQueue removeObjectAtIndex:0];
802        }
803}
804
805- (void)captureOutput:(NSString*)str forExecutable:(AuthorizedExecutable*)exe
806{
807        NSRange marker, eol;
808    [[portLog textStorage] appendAttributedString: [[[NSAttributedString alloc]
809                             initWithString: str] autorelease]];
810        @try {
811                marker = [str rangeOfString:@"--->"];
812                eol = [str rangeOfString:@"\n" options:NSLiteralSearch range:NSMakeRange(marker.location + 4, [str length] - marker.location)];
813                NSLog([str substringWithRange:NSMakeRange(marker.location + 4, eol.location - (marker.location + 4))]);
814        }               
815        @catch (NSException *exception) {
816                // Exceptions will be thrown where "--->" is not in str
817                // Ignore the exceptions since we want to change the status line only if such a line exists
818        }
819    [self performSelector:@selector(scrollToVisible:) withObject:nil afterDelay:0.0];
820}
821
822- (void)executableFinished:(AuthorizedExecutable *)exe withStatus:(int)exeStatus
823{
824        NSLog(@"Launcher finished with status %u", exeStatus);
825        portIsRunning = NO;
826        [status setStringValue:@""];
827        [progressIndicator stopAnimation:nil];
828        if ([taskQueue count]) {
829                [self launchAuthorizedExecutableWithArguments:[taskQueue objectAtIndex:0]];
830                [taskQueue removeObjectAtIndex:0];
831        }
832}
833
834#pragma mark APPLICATION DELEGATES
835
836-(void)applicationWillTerminate:(NSNotification*)anotification
837{
838        [NSApp setApplicationIconImage:[NSImage imageNamed:@"ApplicationIcon"]];
839    [authPortTask unAuthorize];
840        [killTask unAuthorize];
841}
842
843
844@end
Note: See TracBrowser for help on using the repository browser.