~ubuntu-branches/ubuntu/vivid/projectcenter.app/vivid

« back to all changes in this revision

Viewing changes to Framework/PCProjectBuilder.m

  • Committer: Bazaar Package Importer
  • Author(s): Yavor Doganov
  • Date: 2010-06-03 16:04:52 UTC
  • mfrom: (3.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20100603160452-dcsmkjwdtwxuitdo
Tags: 0.5.3~20100601-1
* New upstream release.
* debian/compat: Set to 7.
* debian/control (Section): Change to `gnustep'.
  (Build-Depends): Require debhelper >= 7, remove version constraints
  for libgnustep-gui-dev (obsolete).
  (Depends): Add ${gnustep:Depends}.
  (Standards-Version): Compliant with 3.8.4 as of this release.
  (Vcs-Arch): New field.
  (Description): Do not praise NextStep.
* debian/rules: Export GNUSTEP_MAKEFILES and get rid of gs_make.
  (OPTFLAG): No longer define; rework noopt handling to be compatible
  with gnustep-make/2.4.x (Closes: #581976).
  (build-stamp): Pass GDB=/usr/bin/gdb for the PCDefaultDebugger
  define.
  (install): Replace dh_clean -k with dh_prep.
  (binary-arch): Adjust dh_installchangelogs' argument.  Rework the
  FHS_ME_HARDER snippet; PC's supporting executables are no longer
  installed as Bundles.
* debian/patches/05_link-libs.dpatch: Update; the fix was merged
  upstream, but now -lm is required as well.
* debian/patches/10_bundles-install-dir.dpatch: Remove; obsolete with
  the new way of FHS-compliance handling.
* debian/links: Delete; no longer needed.
* debian/menu: Adjust command.
* debian/source/format:
* debian/README.source:
* debian/preinst: New file.
* debian/copyright: Bump copyright years, add more upstream authors.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
24
24
*/
25
25
 
26
 
#include <AppKit/AppKit.h>
27
 
 
28
 
#include <ProjectCenter/PCDefines.h>
29
 
#include <ProjectCenter/PCSplitView.h>
30
 
#include <ProjectCenter/PCButton.h>
31
 
 
32
 
#include <ProjectCenter/PCFileManager.h>
33
 
 
34
 
#include <ProjectCenter/PCProjectManager.h>
35
 
#include <ProjectCenter/PCProject.h>
36
 
#include <ProjectCenter/PCProjectBuilder.h>
37
 
#include <ProjectCenter/PCProjectBuilderOptions.h>
38
 
 
39
 
#include <ProjectCenter/PCProjectEditor.h>
40
 
#include <Protocols/CodeEditor.h>
41
 
 
42
 
#include <ProjectCenter/PCLogController.h>
43
 
#include <ProjectCenter/PCPrefController.h>
 
26
#import <AppKit/AppKit.h>
 
27
 
 
28
#import <ProjectCenter/PCDefines.h>
 
29
#import <ProjectCenter/PCButton.h>
 
30
 
 
31
#import <ProjectCenter/PCFileManager.h>
 
32
 
 
33
#import <ProjectCenter/PCProjectManager.h>
 
34
#import <ProjectCenter/PCProject.h>
 
35
#import <ProjectCenter/PCProjectWindow.h>
 
36
#import <ProjectCenter/PCProjectBuilder.h>
 
37
#import <ProjectCenter/PCProjectBuilderOptions.h>
 
38
 
 
39
#import <ProjectCenter/PCProjectEditor.h>
 
40
#import <Protocols/CodeEditor.h>
 
41
#import <ProjectCenter/PCSaveModified.h>
 
42
 
 
43
#import <ProjectCenter/PCLogController.h>
 
44
#import <Protocols/Preferences.h>
 
45
 
 
46
#import "../Modules/Preferences/Build/PCBuildPrefs.h"
44
47
 
45
48
#ifndef IMAGE
46
49
#define IMAGE(X) [NSImage imageNamed: X]
54
57
 
55
58
- (id)initWithProject:(PCProject *)aProject
56
59
{
 
60
#ifdef DEBUG
 
61
  NSLog (@"PCProjectBuilder: initWithProject");
 
62
#endif
 
63
 
57
64
  NSAssert(aProject, @"No project specified!");
58
 
 
59
 
//  PCLogInfo(self, @"initWithProject %@", [aProject projectName]);
60
65
  
61
66
  if ((self = [super init]))
62
67
    {
77
82
          PCLogError(self, @"error loading Builder NIB file!");
78
83
          return nil;
79
84
        }
 
85
      [[NSNotificationCenter defaultCenter]
 
86
        addObserver:self
 
87
           selector:@selector(loadPreferences:)
 
88
               name:PCPreferencesDidChangeNotification
 
89
             object:nil];
 
90
      [self loadPreferences:nil];
80
91
    }
81
92
 
82
93
  return self;
84
95
 
85
96
- (void)dealloc
86
97
{
87
 
#ifdef DEVELOPMENT
 
98
#ifdef DEBUG
88
99
  NSLog (@"PCProjectBuilder: dealloc");
89
100
#endif
90
101
 
91
 
  [buildStatusTarget release];
92
 
  [buildTarget release];
93
 
  [buildArgs release];
94
 
  [makePath release];
95
 
 
96
 
//  PCLogInfo(self, @"componentView RC: %i", [componentView retainCount]);
97
 
//  PCLogInfo(self, @"RC: %i", [self retainCount]);
98
 
  [componentView release];
99
 
  [errorArray release];
100
 
  [errorString release];
101
 
  [buildOptions release];
 
102
  [[NSNotificationCenter defaultCenter] removeObserver:self];
 
103
 
 
104
  if ([componentView superview])
 
105
    {
 
106
      [componentView removeFromSuperview];
 
107
    }
 
108
 
 
109
  RELEASE(buildStatusTarget);
 
110
  RELEASE(buildTarget);
 
111
  RELEASE(buildArgs);
 
112
  RELEASE(buildOptions);
 
113
 
 
114
  RELEASE(successSound);
 
115
  RELEASE(failureSound);
 
116
  RELEASE(rootBuildDir);
 
117
  RELEASE(buildTool);
 
118
 
 
119
//  NSLog(@"Project Builder--> componentView RC: %i", 
 
120
//      [componentView retainCount]);
 
121
 
 
122
  RELEASE(componentView);
 
123
  RELEASE(errorArray);
 
124
  RELEASE(errorString);
 
125
 
 
126
//  NSLog(@"Project Builder--> RC: %i", [self retainCount]);
102
127
 
103
128
  [super dealloc];
104
129
}
113
138
      return;
114
139
    }
115
140
 
116
 
  NSLog(@"ProjectBuilder awakeFromNib");
 
141
//  NSLog(@"ProjectBuilder awakeFromNib");
117
142
 
118
143
  [componentView retain];
119
144
  [componentView removeFromSuperview];
120
145
 
 
146
//  NSLog(@"ProjectBuilder awakeFromNib: componentView RC:%i", 
 
147
//      [componentView retainCount]);
 
148
 
121
149
  /*
122
150
   * 4 build Buttons
123
151
   */
159
187
  [errorOutput addTableColumn:errorColumn];
160
188
  [errorOutput setDataSource:self];
161
189
  [errorOutput setBackgroundColor:[NSColor colorWithDeviceRed:0.88
162
 
                                                             green:0.76 
163
 
                                                              blue:0.60 
164
 
                                                             alpha:1.0]];
 
190
                                                        green:0.76 
 
191
                                                         blue:0.60 
 
192
                                                        alpha:1.0]];
165
193
  [errorOutput setDrawsGrid:NO];
166
194
  [errorOutput setTarget:self];
167
195
  [errorOutput setAction:@selector(errorItemClick:)];
178
206
  /*
179
207
   *  Log output
180
208
   */
181
 
  logScroll = [[NSScrollView alloc] 
182
 
    initWithFrame:NSMakeRect (0, 0, 480, 133)];
 
209
  logScroll = [[NSScrollView alloc] initWithFrame:NSMakeRect(0,0,480,133)];
183
210
  [logScroll setHasHorizontalScroller:NO];
184
211
  [logScroll setHasVerticalScroller:YES];
185
212
  [logScroll setBorderType:NSBezelBorder];
209
236
   * Split view
210
237
   */
211
238
  [split addSubview:errorScroll];
212
 
  RELEASE (errorScroll);
 
239
  RELEASE(errorScroll);
213
240
  [split addSubview:logScroll];
214
 
  RELEASE (logScroll);
 
241
  RELEASE(logScroll);
215
242
 
216
243
//  [split adjustSubviews];
217
244
//  [componentView addSubview:split];
225
252
  return componentView;
226
253
}
227
254
 
228
 
- (BOOL)setMakePath
 
255
- (void)loadPreferences:(NSNotification *)aNotification
229
256
{
230
 
  makePath = [[NSUserDefaults standardUserDefaults] objectForKey:BuildTool];
231
 
 
232
 
  if (!makePath || ![[NSFileManager defaultManager] fileExistsAtPath:makePath])
233
 
    {
234
 
      NSRunAlertPanel(@"Build terminated",
235
 
                      @"Build tool not found.\nFile \"%@\" doesn't exist!",
236
 
                      @"OK", nil, nil, makePath);
237
 
      return NO;
238
 
    }
239
 
 
240
 
  return YES;
 
257
  id <PCPreferences> prefs = [[project projectManager] prefController];
 
258
 
 
259
  ASSIGN(successSound, [prefs stringForKey:SuccessSound]);
 
260
  ASSIGN(failureSound, [prefs stringForKey:FailureSound]);
 
261
 
 
262
  ASSIGN(rootBuildDir, [prefs stringForKey:RootBuildDirectory]);
 
263
  ASSIGN(buildTool, [prefs stringForKey:BuildTool]);
 
264
 
 
265
  promptOnClean = [prefs boolForKey:PromptOnClean];
241
266
}
242
267
 
243
268
- (void)updateTargetField
248
273
  args = [[[project projectDict] objectForKey:PCBuilderArguments] 
249
274
    componentsJoinedByString:@" "];
250
275
 
 
276
  if (!args) args = @" ";
 
277
 
251
278
  s = [NSString stringWithFormat:@"%@ with args '%@'", buildTarget, args];
252
279
 
253
280
  [targetField setStringValue:s];
302
329
      ![instDir isEqualToString:@"SYSTEM"] &&
303
330
      ![instDir isEqualToString:@"USER"] &&
304
331
      ![instDir isEqualToString:@"NETWORK"] &&
305
 
      ![instDir isEqualToString:@""])
 
332
      ![instDir isEqualToString:@""] &&
 
333
      ([instDir isAbsolutePath] || [instDir characterAtIndex:0] == '$'))
306
334
    {
307
335
      [args addObject:[NSString stringWithFormat:@"DESTDIR=%@", instDir]];
308
336
    }
309
337
 
310
338
  [args addObjectsFromArray:[projectDict objectForKey:PCBuilderArguments]];
311
339
 
312
 
  // Get arguments from options
313
 
  if ([[projectDict objectForKey:PCBuilderVerbose] isEqualToString:@"YES"])
314
 
    { // default is 'messages=no'
315
 
      [args addObject:@"messages=yes"];
316
 
    }
 
340
  // --- Get arguments from options
317
341
  if ([[projectDict objectForKey:PCBuilderDebug] isEqualToString:@"NO"])
318
342
    { // default is 'debug=yes'
319
343
      [args addObject:@"debug=no"];
326
350
    { // default is 'shared=yes'
327
351
      [args addObject:@"shared=no"];
328
352
    }
 
353
  // Always add 'messages=yes' argument. Build output parsing assumes this.
 
354
  [args addObject:@"messages=yes"];
 
355
  // "Verbose ouput" option (Build Options panel) just toogle if build shows
 
356
  // as with argument 'messages=yes' or not.
 
357
  if ([[projectDict objectForKey:PCBuilderVerbose] isEqualToString:@"YES"])
 
358
    {
 
359
      verboseBuilding = YES;
 
360
    }
 
361
  else
 
362
    {
 
363
      verboseBuilding = NO;
 
364
    }
329
365
 
330
366
  return args;
331
367
}
338
374
      return;
339
375
    }
340
376
 
 
377
  // Set build arguments
341
378
  [buildArgs addObject:buildTarget];
342
 
 
343
 
  // Set build arguments
344
379
  [buildArgs addObjectsFromArray:[self buildArguments]];
345
380
 
346
 
  NSLog(@"ProjectBuilder arguments: %@", buildArgs);
 
381
//  NSLog(@"ProjectBuilder arguments: %@", buildArgs);
347
382
 
348
383
  currentEL = ELNone;
349
384
  lastEL = ELNone;
350
385
  nextEL = ELNone;
351
386
  lastIndentString = @"";
352
387
 
353
 
  currentBuildPath = [[NSMutableArray alloc] initWithCapacity:1];
354
 
  [currentBuildPath addObject:[project projectPath]];
355
 
  currentBuildFile = [[NSMutableString alloc] initWithString:@""];
356
 
 
357
388
  buildStatus = [NSString stringWithString:@"Building..."];
358
389
  [buildStatusTarget setString:@"Build"];
359
390
  [cleanButton setEnabled:NO];
360
 
  [self build:self];
361
391
  _isBuilding = YES;
 
392
  [self build:self];
362
393
}
363
394
 
364
395
- (void)startClean:(id)sender
368
399
      return;
369
400
    }
370
401
 
371
 
  if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation]
372
 
      objectForKey:PromptOnClean] isEqualToString:@"YES"])
 
402
  if (promptOnClean)
373
403
    {
374
 
      if (NSRunAlertPanel(@"Clean Project?",
 
404
      if (NSRunAlertPanel(@"Project Clean",
375
405
                          @"Do you really want to clean project '%@'?",
376
 
                          @"Yes", @"No", nil, [project projectName])
 
406
                          @"Clean", @"Stop", nil, [project projectName])
377
407
          == NSAlertAlternateReturn)
378
408
        {
379
409
          [cleanButton setState:NSOffState];
381
411
        }
382
412
    }
383
413
 
 
414
  // Set build arguments
 
415
  [buildArgs addObject:@"clean"];
 
416
  [buildArgs addObjectsFromArray:[self buildArguments]];
 
417
 
384
418
  buildStatus = [NSString stringWithString:@"Cleaning..."];
385
419
  [buildStatusTarget setString:@"Clean"];
386
 
  [buildArgs addObject:@"clean"];
387
420
  [buildButton setEnabled:NO];
388
 
  [self build:self];
389
421
  _isCleaning = YES;
 
422
  [self build:self];
390
423
}
391
424
 
392
425
- (BOOL)stopMake:(id)sender
393
426
{
394
 
  // [makeTask isRunning] doesn't work here.
395
 
  // "waitpid 7045, result -1, error No child processes" is printed.
396
 
  if (makeTask)
 
427
  if (makeTask && [makeTask isRunning])
397
428
    {
398
429
      PCLogStatus(self, @"task will terminate");
399
430
      NS_DURING
418
449
 
419
450
- (void)cleanupAfterMake
420
451
{
 
452
  NSString *statusString;
 
453
 
421
454
  if (_isBuilding || _isCleaning)
422
455
    {
423
 
      [statusField setStringValue:[NSString stringWithFormat: 
424
 
        @"%@ - %@ terminated", [project projectName], buildStatusTarget]];
 
456
      statusString =[NSString stringWithFormat: 
 
457
        @"%@ - %@ terminated", [project projectName], buildStatusTarget];
 
458
      [statusField setStringValue:statusString];
 
459
      [[project projectWindow] updateStatusLineWithText:statusString];
425
460
    }
426
461
 
427
462
  // Restore buttons state
428
 
  if ([buildStatusTarget isEqualToString:@"Build"])
 
463
  if (_isBuilding)
429
464
    {
430
465
      [buildButton setState:NSOffState];
431
466
      [cleanButton setEnabled:YES];
 
467
      _isBuilding = NO;
432
468
    }
433
 
  else if ([buildStatusTarget isEqualToString:@"Clean"])
 
469
  else if (_isCleaning)
434
470
    {
435
471
      [cleanButton setState:NSOffState];
436
472
      [buildButton setEnabled:YES];
 
473
      _isCleaning = NO;
437
474
    }
438
475
 
439
476
  [buildArgs removeAllObjects];
440
477
  [buildStatusTarget setString:@"Default"];
441
478
 
442
 
  if (_isBuilding)
443
 
    {
444
 
      [currentBuildPath release];
445
 
      [currentBuildFile release];
446
 
    }
447
 
 
448
 
  _isBuilding = NO;
449
 
  _isCleaning = NO;
 
479
  // Initiated in [self build:]
 
480
  [currentBuildPath release];
 
481
  [currentBuildFile release];
450
482
}
451
483
 
452
484
// --- Actions
453
485
- (BOOL)prebuildCheck
454
486
{
455
 
  PCPrefController *prefs = [PCPrefController sharedPCPreferences];
456
 
  PCFileManager    *pcfm = [PCFileManager defaultManager];
457
 
  NSFileManager    *fm = [NSFileManager defaultManager];
458
 
  NSString         *buildDir = [prefs objectForKey:RootBuildDirectory];
459
 
  NSString         *projectBuildDir;
 
487
  PCFileManager   *pcfm = [PCFileManager defaultManager];
 
488
  NSFileManager   *fm = [NSFileManager defaultManager];
 
489
  NSString        *buildDir;
 
490
  PCProjectEditor *projectEditor;
 
491
  int             ret;
460
492
 
461
 
  // Checking prerequisites
 
493
  // Checking for project 'edited' state 
462
494
  if ([project isProjectChanged])
463
495
    {
464
 
      if (NSRunAlertPanel(@"Project Changed!",
465
 
                          @"Should it be saved first?",
466
 
                          @"Yes", @"No", nil) == NSAlertDefaultReturn) 
 
496
      ret = NSRunAlertPanel(@"Project Build",
 
497
                            @"Project was changed and not saved.\n"
 
498
                            @"Do you want to save project before building it?",
 
499
                            @"Stop Build", @"Save and Build", nil);
 
500
      switch (ret)
467
501
        {
 
502
        case NSAlertDefaultReturn: // Stop Build
 
503
          return NO;
 
504
          break;
 
505
 
 
506
        case NSAlertAlternateReturn: // Save Project
468
507
          [project save];
 
508
          break;
469
509
        }
470
510
    }
471
511
  else
472
512
    {
473
 
      // Synchronize PC.project and generated files just for case
 
513
      // Synchronize PC.project and generate files
474
514
      [project save];
475
515
    }
476
516
 
477
 
  // Get make tool path
478
 
  makePath = [[NSUserDefaults standardUserDefaults] objectForKey:BuildTool];
 
517
  // Checking if edited files exist
 
518
  projectEditor = [project projectEditor];
 
519
  if ([projectEditor hasModifiedFiles])
 
520
    {
 
521
      if (!PCRunSaveModifiedFilesPanel(projectEditor, 
 
522
                                       @"Save and Build",
 
523
                                       @"Build Anyway",
 
524
                                       @"Cancel"))
 
525
        {
 
526
          return NO;
 
527
        }
 
528
    }
479
529
 
480
 
  if (!makePath || ![[NSFileManager defaultManager] fileExistsAtPath:makePath])
 
530
  // Check build tool path
 
531
  if (!buildTool || ![fm fileExistsAtPath:buildTool])
481
532
    {
482
 
      NSRunAlertPanel(@"Build terminated",
483
 
                      @"Build tool not found.\nFile \"%@\" doesn't exist!",
484
 
                      @"OK", nil, nil, makePath);
 
533
      NSRunAlertPanel(@"Project Build",
 
534
                      @"Build tool '%@' not found. Check preferences.\n"
 
535
                      @"Build will be terminated.",
 
536
                      @"Close", nil, nil, buildTool);
485
537
      return NO;
486
538
    }
487
539
 
488
540
  // Create root build directory if not exist
489
 
  projectBuildDir = [NSString stringWithFormat:@"%@.build", 
490
 
                  [project projectName]];
491
 
  projectBuildDir = [buildDir stringByAppendingPathComponent:projectBuildDir];
492
 
  if (![fm fileExistsAtPath:buildDir] ||
493
 
      ![fm fileExistsAtPath:projectBuildDir])
 
541
  if (rootBuildDir && ![rootBuildDir isEqualToString:@""])
494
542
    {
495
 
      [pcfm createDirectoriesIfNeededAtPath:projectBuildDir];
 
543
      buildDir = [NSString 
 
544
        stringWithFormat:@"%@.build", [project projectName]];
 
545
      buildDir = [rootBuildDir stringByAppendingPathComponent:buildDir];
 
546
      if (![fm fileExistsAtPath:rootBuildDir] || 
 
547
          ![fm fileExistsAtPath:buildDir])
 
548
        {
 
549
          [pcfm createDirectoriesIfNeededAtPath:buildDir];
 
550
        }
496
551
    }
497
552
 
498
553
  return YES;
500
555
 
501
556
- (void)build:(id)sender
502
557
{
503
 
  NSPipe *logPipe;
504
 
  NSPipe *errorPipe;
505
 
 
506
 
  // TODO: Support build options!!!
507
 
  //  NSDictionary        *optionDict = [project buildOptions];
 
558
  // Make runtime vars
 
559
  // Released in [self cleanupAfterMake]
 
560
  currentBuildPath = [[NSMutableString alloc] 
 
561
    initWithString:[project projectPath]];
 
562
  currentBuildFile = [[NSMutableString alloc] initWithString:@""];
508
563
 
509
564
  // Checking build conditions
510
565
  if ([self prebuildCheck] == NO)
514
569
    }
515
570
 
516
571
  // Prepearing to building
517
 
  logPipe = [NSPipe pipe];
518
 
  readHandle = [logPipe fileHandleForReading];
519
 
  [readHandle waitForDataInBackgroundAndNotify];
 
572
  _isLogging = YES;
 
573
  stdOutPipe = [[NSPipe alloc] init];
 
574
  stdOutHandle = [stdOutPipe fileHandleForReading];
 
575
  [stdOutHandle waitForDataInBackgroundAndNotify];
520
576
 
521
577
  [NOTIFICATION_CENTER addObserver:self 
522
578
                          selector:@selector(logStdOut:)
523
579
                              name:NSFileHandleDataAvailableNotification
524
 
                            object:readHandle];
525
 
  _isLogging = YES;
 
580
                            object:stdOutHandle];
526
581
 
527
 
  errorPipe = [NSPipe pipe];
528
 
  errorReadHandle = [errorPipe fileHandleForReading];
529
 
  [errorReadHandle waitForDataInBackgroundAndNotify];
 
582
  _isErrorLogging = YES;
 
583
  stdErrorPipe = [[NSPipe alloc] init];
 
584
  stdErrorHandle = [stdErrorPipe fileHandleForReading];
 
585
  [stdErrorHandle waitForDataInBackgroundAndNotify];
530
586
 
531
587
  [NOTIFICATION_CENTER addObserver:self 
532
588
                          selector:@selector(logErrOut:) 
533
589
                              name:NSFileHandleDataAvailableNotification
534
 
                            object:errorReadHandle];
535
 
  _isErrorLogging = YES;
 
590
                            object:stdErrorHandle];
 
591
 
536
592
  [errorsCountField setStringValue:[NSString stringWithString:@""]];
537
593
  errorsCount = 0;
538
594
  warningsCount = 0;
539
595
 
540
596
  [statusField setStringValue:buildStatus];
 
597
  [[project projectWindow] updateStatusLineWithText:buildStatus];
541
598
 
542
599
  // Run make task
543
600
  [logOutput setString:@""];
552
609
  makeTask = [[NSTask alloc] init];
553
610
  [makeTask setArguments:buildArgs];
554
611
  [makeTask setCurrentDirectoryPath:[project projectPath]];
555
 
  [makeTask setLaunchPath:makePath];
556
 
  [makeTask setStandardOutput:logPipe];
557
 
  [makeTask setStandardError:errorPipe];
 
612
  [makeTask setLaunchPath:buildTool];
 
613
  [makeTask setStandardOutput:stdOutPipe];
 
614
  [makeTask setStandardError:stdErrorPipe];
 
615
 
 
616
  [self logBuildString:
 
617
    [NSString stringWithFormat:@"=== %@ started ===", buildStatusTarget]
 
618
               newLine:YES];
558
619
 
559
620
  NS_DURING
560
621
    {
576
637
 
577
638
- (void)buildDidTerminate:(NSNotification *)aNotif
578
639
{
579
 
  int status;
 
640
  int      status;
 
641
  NSString *logString;
 
642
  NSString *statusString;
580
643
 
581
644
  if ([aNotif object] != makeTask)
582
645
    {
583
646
      return;
584
647
    }
585
648
 
586
 
  NSLog(@"task did terminate");
 
649
//  NSLog(@"task did terminate");
587
650
 
588
651
  [NOTIFICATION_CENTER removeObserver:self 
589
652
                                 name:NSTaskDidTerminateNotification
601
664
  NS_ENDHANDLER
602
665
 
603
666
  // Finish task
 
667
  // TODO: Strange behaviour of pipe and file handlers alloc/release. Also
 
668
  // they have big retain count here (2 or 3). Why? Notification retains it?
604
669
  RELEASE(makeTask);
605
670
  makeTask = nil;
606
671
 
607
 
  // Wait for logging end
 
672
  // Wait while logging ends
608
673
  while (_isLogging || _isErrorLogging) 
609
674
    {
610
675
      [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
611
676
                               beforeDate:[NSDate distantFuture]];
612
677
    }
613
 
    
 
678
 
 
679
  RELEASE(stdOutPipe);
 
680
  RELEASE(stdErrorPipe);
 
681
 
614
682
  [self updateErrorsCountField];
615
683
 
616
684
  if (status == 0)
617
685
    {
618
 
      [self logString: 
619
 
        [NSString stringWithFormat:@"=== %@ succeeded! ===", buildStatusTarget] 
620
 
                             error:NO
621
 
                           newLine:YES];
622
 
      [statusField setStringValue:[NSString stringWithFormat: 
623
 
        @"%@ - %@ succeeded", [project projectName], buildStatusTarget]];
 
686
      logString = [NSString stringWithFormat:@"=== %@ succeeded! ===", 
 
687
                buildStatusTarget];
 
688
      statusString = [NSString stringWithFormat:@"%@ - %@ succeeded", 
 
689
                   [project projectName], buildStatusTarget];
624
690
    } 
625
691
  else
626
692
    {
627
 
      [self logString: 
628
 
        [NSString stringWithFormat:@"=== %@ terminated! ===", buildStatusTarget]
629
 
                             error:NO
630
 
                           newLine:YES];
 
693
      logString = [NSString stringWithFormat:@"=== %@ terminated! ===", 
 
694
                buildStatusTarget];
631
695
      if (errorsCount > 0)
632
696
        {
633
 
          [statusField setStringValue:[NSString stringWithFormat: 
 
697
          statusString = [NSString stringWithFormat: 
634
698
            @"%@ - %@ failed (%i errors)", 
635
 
            [project projectName], buildStatusTarget, errorsCount]];
 
699
            [project projectName], buildStatusTarget, errorsCount];
636
700
        }
637
701
      else
638
702
        {
639
 
          [statusField setStringValue:[NSString stringWithFormat: 
640
 
            @"%@ - %@ failed", 
641
 
            [project projectName], buildStatusTarget]];
 
703
          statusString = [NSString stringWithFormat:@"%@ - %@ failed", 
 
704
                       [project projectName], buildStatusTarget];
642
705
        }
643
706
    }
 
707
  [statusField setStringValue:statusString];
 
708
  [[project projectWindow] updateStatusLineWithText:statusString];
 
709
  [self logBuildString:logString newLine:YES];
644
710
 
645
711
  // Run post process if configured
646
712
/*  if (status && postProcess)
649
715
      postProcess = NULL;
650
716
    }*/
651
717
 
652
 
  _isBuilding = NO;
653
 
  _isCleaning = NO;
654
718
  [self cleanupAfterMake];
655
719
}
656
720
 
657
 
- (void)logStdOut:(NSNotification *)aNotif
658
 
{
659
 
  NSData *data;
660
 
 
661
 
//  NSLog(@"logStdOut");
662
 
 
663
 
  if ((data = [readHandle availableData]) && [data length] > 0)
664
 
    {
665
 
      [self logData:data error:NO];
666
 
    }
667
 
 
668
 
  if (makeTask)
669
 
    {
670
 
      [readHandle waitForDataInBackgroundAndNotify];
671
 
    }
672
 
  else
673
 
    {
674
 
      _isLogging = NO;
675
 
      [NOTIFICATION_CENTER removeObserver:self 
676
 
                                     name:NSFileHandleDataAvailableNotification
677
 
                                   object:readHandle];
678
 
    }
679
 
}
680
 
 
681
 
- (void)logErrOut:(NSNotification *)aNotif
682
 
{
683
 
  NSData *data;
684
 
 
685
 
//  NSLog(@"logErrOut");
686
 
  
687
 
  if ((data = [errorReadHandle availableData]) && [data length] > 0)
688
 
    {
689
 
      [self logData:data error:YES];
690
 
    }
691
 
 
692
 
  if (makeTask)
693
 
    {
694
 
      [errorReadHandle waitForDataInBackgroundAndNotify];
695
 
    }
696
 
  else
697
 
    {
698
 
      _isErrorLogging = NO;
699
 
      [NOTIFICATION_CENTER removeObserver:self 
700
 
                                     name:NSFileHandleDataAvailableNotification
701
 
                                   object:errorReadHandle];
702
 
    }
703
 
}
 
721
// --- BuilderOptions delegate
 
722
- (void)targetDidSet:(NSString *)target
 
723
{
 
724
  [buildTarget setString:target];
 
725
  [self updateTargetField];
 
726
}
 
727
 
 
728
@end
 
729
 
 
730
@implementation PCProjectBuilder (Logging)
704
731
 
705
732
- (void)updateErrorsCountField
706
733
{
707
734
  NSString *string;
708
 
  NSString *errorsString = [NSString stringWithString:@""];;
 
735
  NSString *errorsString = [NSString stringWithString:@""];
709
736
  NSString *warningsString = [NSString stringWithString:@""];
710
737
 
711
738
  if (errorsCount > 0)
738
765
  [errorsCountField setStringValue:string];
739
766
}
740
767
 
741
 
// --- BuilderOptions delgate
742
 
- (void)targetDidSet:(NSString *)target
743
 
{
744
 
  [buildTarget setString:target];
745
 
  [self updateTargetField];
746
 
}
747
 
 
748
 
@end
749
 
 
750
 
@implementation PCProjectBuilder (BuildLogging)
751
 
 
752
 
- (void)logString:(NSString *)str
753
 
            error:(BOOL)yn
754
 
          newLine:(BOOL)newLine
755
 
{
756
 
//  NSTextView *out = (yn) ? errorOutput : logOutput;
757
 
  NSTextView *out = logOutput;
758
 
 
759
 
  [out replaceCharactersInRange:
760
 
    NSMakeRange([[out string] length],0) withString:str];
761
 
 
762
 
  if (newLine)
763
 
    {
764
 
      [out replaceCharactersInRange:
765
 
        NSMakeRange([[out string] length], 0) withString:@"\n"];
766
 
    }
767
 
  else
768
 
    {
769
 
      [out replaceCharactersInRange:
770
 
        NSMakeRange([[out string] length], 0) withString:@" "];
771
 
    }
772
 
 
773
 
  [out scrollRangeToVisible:NSMakeRange([[out string] length], 0)];
774
 
  [out setNeedsDisplay:YES];
775
 
}
776
 
 
 
768
// --- Data notifications
 
769
// Both methods make call to dipatcher logData:error:
 
770
- (void)logStdOut:(NSNotification *)aNotif
 
771
{
 
772
  NSData *data;
 
773
 
 
774
  if ((data = [stdOutHandle availableData]) && [data length] > 0)
 
775
    {
 
776
      [self logData:data error:NO];
 
777
    }
 
778
 
 
779
  if (makeTask)
 
780
    {
 
781
      [stdOutHandle waitForDataInBackgroundAndNotify];
 
782
    }
 
783
  else
 
784
    {
 
785
      [NOTIFICATION_CENTER removeObserver:self 
 
786
                                     name:NSFileHandleDataAvailableNotification
 
787
                                   object:stdOutHandle];
 
788
      _isLogging = NO;
 
789
    }
 
790
}
 
791
 
 
792
- (void)logErrOut:(NSNotification *)aNotif
 
793
{
 
794
  NSData *data;
 
795
 
 
796
  if ((data = [stdErrorHandle availableData]) && [data length] > 0)
 
797
    {
 
798
      [self logData:data error:YES];
 
799
    }
 
800
 
 
801
  if (makeTask)
 
802
    {
 
803
      [stdErrorHandle waitForDataInBackgroundAndNotify];
 
804
    }
 
805
  else
 
806
    {
 
807
      [NOTIFICATION_CENTER removeObserver:self 
 
808
                                     name:NSFileHandleDataAvailableNotification
 
809
                                   object:stdErrorHandle];
 
810
      _isErrorLogging = NO;
 
811
    }
 
812
}
 
813
 
 
814
// --- Dispatching
777
815
- (void)logData:(NSData *)data
778
 
          error:(BOOL)yn
 
816
          error:(BOOL)isError
779
817
{
780
818
  NSString *dataString;
781
819
  NSRange  newLineRange;
788
826
                            
789
827
  // Process new data
790
828
  lineRange.location = 0;
 
829
  newLineRange.location = 0;
 
830
  // 'errorString' collects data across logData:error: calls until 
 
831
  // new line character is appeared.
791
832
  [errorString appendString:dataString];
792
833
  while (newLineRange.location != NSNotFound)
793
834
    {
805
846
          lineString = [errorString substringWithRange:lineRange];
806
847
          [errorString deleteCharactersInRange:lineRange];
807
848
 
808
 
          // Send it
809
 
          if (_isBuilding)
810
 
            {
811
 
              [self parseBuildLine:lineString];
812
 
              if (yn)
813
 
                {
814
 
                  [self logErrorString:lineString];
815
 
                }
816
 
            }
817
 
          [self logString:lineString error:yn newLine:NO];
 
849
          // Send it to error view
 
850
          // Do not process make errors in other mode but building. Maybe
 
851
          // some day...
 
852
          if (_isBuilding && isError)
 
853
            {
 
854
              [self logErrorString:lineString];
 
855
            }
 
856
          // Cleaning or building standard out string
 
857
          if (!isError || verboseBuilding)
 
858
            {
 
859
              [self logBuildString:lineString newLine:NO];
 
860
            }
818
861
        }
819
862
      else
820
863
        {
826
869
  RELEASE(dataString);
827
870
}
828
871
 
829
 
- (void)parseBuildLine:(NSString *)string
830
 
{
831
 
  NSArray  *components = [string componentsSeparatedByString:@" "];
832
 
 
833
 
  if (!components)
834
 
    {
835
 
      return;
836
 
    }
837
 
 
838
 
  if ([components containsObject:@"Compiling"] &&
839
 
      [components containsObject:@"file"])
840
 
    {
841
 
      NSLog(@"Current build file: %@", [components objectAtIndex:3]);
842
 
      [currentBuildFile setString:[components objectAtIndex:3]];
843
 
    }
844
 
  else if ([components containsObject:@"Entering"] &&
845
 
           [components containsObject:@"directory"])
846
 
    {
847
 
      NSString *path;
848
 
      NSString *pathComponent = [components objectAtIndex:3];
849
 
 
850
 
      NSLog(@"Go down to %@", pathComponent);
 
872
@end
 
873
 
 
874
@implementation PCProjectBuilder (BuildLogging)
 
875
 
 
876
// --- Parsing utilities
 
877
- (BOOL)line:(NSString *)lineString startsWithString:(NSString *)substring
 
878
{
 
879
  int      position = 0;
 
880
  NSRange  range = NSMakeRange(position,1);
 
881
 
 
882
  while ([[lineString substringFromRange:range] isEqualToString:@" "])
 
883
    {
 
884
      range.location = ++position;
 
885
    }
 
886
 
 
887
/*  NSLog(@"Line '%@' position: %i substring '%@'", 
 
888
        lineString, position, substring);*/
 
889
 
 
890
  range = [lineString rangeOfString:substring];
 
891
  if ((range.location == NSNotFound) ||
 
892
      (range.location != position))
 
893
    {
 
894
      return NO;
 
895
    }
 
896
 
 
897
  return YES;
 
898
}
 
899
 
 
900
// Clean leading spaces and return cleaned array of components
 
901
- (NSArray *)componentsOfLine:(NSString *)lineString
 
902
{
 
903
  NSArray        *lineComponents;
 
904
  NSMutableArray *tempComponents;
 
905
 
 
906
  lineComponents = [lineString componentsSeparatedByString:@" "];
 
907
  tempComponents = [NSMutableArray arrayWithArray:lineComponents];
 
908
 
 
909
  while ([[tempComponents objectAtIndex:0] isEqualToString:@""])
 
910
    {
 
911
      [tempComponents removeObjectAtIndex:0];
 
912
    }
 
913
 
 
914
  return tempComponents;
 
915
}
 
916
 
 
917
// Line starts with 'gmake' or 'make'.
 
918
// Changes 'currentBuildPath' if line starts with 
 
919
// "Entering directory" or "Leaving directory".
 
920
// For example: 
 
921
// gmake[1]: Entering directory '/Users/me/Project/Subproject.subproj'
 
922
- (void)parseMakeLine:(NSString *)lineString
 
923
{
 
924
  NSMutableArray *makeLineComponents;
 
925
  NSString       *makeLine;
 
926
  NSString       *pathComponent;
 
927
  NSString       *path;
 
928
 
 
929
//  NSLog(@"parseMakeLine: %@", lineString);
 
930
 
 
931
  makeLineComponents = [NSMutableArray 
 
932
    arrayWithArray:[lineString componentsSeparatedByString:@" "]];
 
933
 
 
934
  // Don't check for item at index 0 contents (it's 'gmake[1]:' or 'make[1]:') 
 
935
  // just remove it.
 
936
  [makeLineComponents removeObjectAtIndex:0];
 
937
  makeLine = [makeLineComponents componentsJoinedByString:@" "];
 
938
 
 
939
  if ([self line:makeLine startsWithString:@"Entering directory"])
 
940
    {
 
941
      pathComponent = [makeLineComponents objectAtIndex:2];
851
942
      path = [pathComponent
852
943
        substringWithRange:NSMakeRange(1,[pathComponent length]-3)]; 
853
 
      [currentBuildPath addObject:path];
854
 
      NSLog(@"%@", [currentBuildPath lastObject]);
855
 
    }
856
 
  else if ([components containsObject:@"Leaving"] &&
857
 
           [components containsObject:@"directory"])
858
 
    {
859
 
      NSLog(@"Go up from %@", [components objectAtIndex:3]);
860
 
      [currentBuildPath removeLastObject];
861
 
      NSLog(@"%@", [currentBuildPath lastObject]);
 
944
//      NSLog(@"Go down to %@", path);
 
945
      [currentBuildPath setString:path];
 
946
    }
 
947
  else if ([self line:makeLine startsWithString:@"Leaving directory"])
 
948
    {
 
949
//      NSLog(@"Go up from %@", [makeLineComponents objectAtIndex:2]);
 
950
      [currentBuildPath 
 
951
        setString:[currentBuildPath stringByDeletingLastPathComponent]];
 
952
    }
 
953
//  NSLog(@"Current build path: %@", currentBuildPath);
 
954
}
 
955
 
 
956
// Should return:
 
957
// 'Compiling ...'
 
958
// 'Linking ...'
 
959
// Also updates currentBuildFile
 
960
- (NSString *)parseCompilerLine:(NSString *)lineString
 
961
{
 
962
  NSArray  *lineComponents = [self componentsOfLine:lineString];
 
963
  NSString *outputString = nil;
 
964
 
 
965
  if ([lineComponents containsObject:@"-c"])
 
966
    {
 
967
      [currentBuildFile setString:[lineComponents objectAtIndex:1]];
 
968
      outputString = [NSString 
 
969
        stringWithFormat:@" Compiling %@...\n", currentBuildFile];
 
970
    }
 
971
  else if ([lineComponents containsObject:@"-rdynamic"])
 
972
    {
 
973
      outputString = [NSString 
 
974
        stringWithFormat:@" Linking %@...\n", 
 
975
        [lineComponents objectAtIndex:[lineComponents indexOfObject:@"-o"]+1]];
 
976
    }
 
977
 
 
978
  return outputString;
 
979
}
 
980
// --- Parsing utilities end
 
981
 
 
982
// Log output
 
983
- (void)logBuildString:(NSString *)string
 
984
               newLine:(BOOL)newLine
 
985
{
 
986
  NSString *logString = [self parseBuildLine:string];
 
987
 
 
988
  if (!logString)
 
989
    {
 
990
      return;
 
991
    }
 
992
 
 
993
  [logOutput replaceCharactersInRange:
 
994
    NSMakeRange([[logOutput string] length],0) withString:logString];
 
995
 
 
996
  if (newLine)
 
997
    {
 
998
      [logOutput replaceCharactersInRange:
 
999
        NSMakeRange([[logOutput string] length], 0) withString:@"\n"];
 
1000
    }
 
1001
 
 
1002
  [logOutput scrollRangeToVisible:NSMakeRange([[logOutput string] length], 0)];
 
1003
  [logOutput setNeedsDisplay:YES];
 
1004
}
 
1005
 
 
1006
// Standard out is parsed for detection of directory, file, etc.
 
1007
// Gets complete line (ended with '\n') as argument
 
1008
- (NSString *)parseBuildLine:(NSString *)string
 
1009
{
 
1010
  NSArray  *components = [self componentsOfLine:string];
 
1011
  NSString *parsedString = nil;
 
1012
 
 
1013
  if (!components)
 
1014
    {
 
1015
      return nil;
 
1016
    }
 
1017
 
 
1018
  if ([self line:string startsWithString:@"gmake"] ||
 
1019
      [self line:string startsWithString:@"make"])
 
1020
    {// Do current path detection
 
1021
      [self parseMakeLine:string];
 
1022
    }
 
1023
  else if ([self line:string startsWithString:@"gcc"])
 
1024
    {// Parse compiler output
 
1025
      parsedString = [self parseCompilerLine:string];
 
1026
    }
 
1027
  else if ([self line:string startsWithString:@"Making"] ||
 
1028
           [self line:string startsWithString:@"==="])
 
1029
    {// It's a gnustep-make and self output
 
1030
      parsedString = string;
 
1031
    }
 
1032
 
 
1033
  if (parsedString && ![self line:parsedString startsWithString:@"==="])
 
1034
    {
 
1035
      [statusField setStringValue:parsedString];
 
1036
      [[project projectWindow] updateStatusLineWithText:parsedString];
 
1037
    }
 
1038
 
 
1039
  if (verboseBuilding)
 
1040
    {
 
1041
      return string;
 
1042
    }
 
1043
  else
 
1044
    {
 
1045
      return parsedString;
862
1046
    }
863
1047
}
864
1048
 
866
1050
 
867
1051
@implementation PCProjectBuilder (ErrorLogging)
868
1052
 
 
1053
// Entry point for error logging
869
1054
- (void)logErrorString:(NSString *)string
870
1055
{
871
1056
  NSArray *items;
879
1064
    }
880
1065
}
881
1066
 
882
 
 
 
1067
// Used for warning or error message retrieval
883
1068
- (NSString *)lineTail:(NSString*)line afterString:(NSString*)string
884
1069
{
885
1070
  NSRange substrRange;
952
1137
      NSString *substr;
953
1138
 
954
1139
      // file and includedFile
955
 
      file = [[currentBuildPath lastObject] 
 
1140
      file = [currentBuildPath  
956
1141
        stringByAppendingPathComponent:currentBuildFile];
957
1142
      if (lastEL == ELIncluded 
958
1143
          || [[components objectAtIndex:0] isEqualToString:lastIncludedFile])
959
1144
        {// first message after "In file included from"
960
1145
//        NSLog(@"Inlcuded File: %@", file);
961
1146
          includedFile = [components objectAtIndex:0];
962
 
          file = includedFile;
 
1147
          file = 
 
1148
            [currentBuildPath stringByAppendingPathComponent:includedFile];
963
1149
          currentEL = ELIncludedError;
964
1150
        }
965
1151
      else
1088
1274
  return items;
1089
1275
}
1090
1276
 
 
1277
// --- Error output table delegate methods
1091
1278
- (int)numberOfRowsInTableView:(NSTableView *)aTableView
1092
1279
{
1093
1280
  if (errorArray != nil && aTableView == errorOutput)
1128
1315
  if (editor)
1129
1316
    {
1130
1317
      position = NSPointFromString([error objectForKey:@"Position"]);
 
1318
      [projectEditor orderFrontEditorForFile:[error objectForKey:@"File"]];
1131
1319
      [editor scrollToLineNumber:(unsigned int)position.x];
1132
1320
 
1133
1321
/*      NSLog(@"%i: %@(%@): %@",