96 LastPackage := something. |
96 LastPackage := something. |
97 ! ! |
97 ! ! |
98 |
98 |
99 !SourceCodeManagerUtilities class methodsFor:'utilities'! |
99 !SourceCodeManagerUtilities class methodsFor:'utilities'! |
100 |
100 |
101 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName |
101 setPackageOfAllMethodsIn:aClass to:aPackage |
102 "open a dialog asking for a source container; |
102 "make all methods belong to the classes project" |
103 return a dictionary containing module, package and filename, |
103 |
104 or nil if canceled." |
104 |anyChange anyChangeHere| |
105 |
105 |
106 ^ self |
106 anyChange := false. |
107 askForContainer:boxText title:title note:notice |
107 aClass withAllPrivateClassesDo:[:eachClass | |
108 initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName |
108 anyChangeHere := false. |
109 forNewContainer:true |
109 eachClass instAndClassSelectorsAndMethodsDo:[:sel :mthd | |
110 ! |
110 mthd package ~= aPackage ifTrue:[ |
111 |
111 mthd setPackage:aPackage. |
112 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName forNewContainer:forNewContainer |
112 anyChangeHere := true. |
113 "open a dialog asking for a source container; |
113 ]. |
114 return a dictionary containing module, package and filename, |
114 ]. |
115 or nil if canceled." |
115 anyChangeHere ifTrue:[ |
116 |
116 eachClass changed:#projectOrganization |
117 |box y component resources answer |
117 ]. |
118 moduleHolder packageHolder fileNameHolder |
118 anyChangeHere ifTrue:[anyChange := true]. |
119 module package fileName |
119 ]. |
120 knownContainers knownPackages packageUpdater |
120 anyChange ifTrue:[ |
121 packageBoxComponent fileNameBoxComponent fileNameUpdater| |
121 Smalltalk changed:#projectOrganization |
122 |
122 ]. |
123 knownContainers := Set new. |
123 ^ anyChange |
124 Smalltalk allClassesDo:[:cls | |pckg| |
124 ! |
125 pckg := cls package. |
125 |
126 pckg size > 0 ifTrue:[ |
126 sourceCodeManagerFor:aClass |
127 knownContainers add:(pckg upTo:$:) |
127 |mgr| |
128 ] |
128 |
129 ]. |
129 mgr := (aClass sourceCodeManager). |
130 knownContainers := knownContainers asOrderedCollection. |
130 mgr isNil ifTrue:[ |
131 knownContainers := knownContainers select:[:module | module isBlank not]. |
131 SourceCodeManager isNil ifTrue:[ |
132 knownContainers sort. |
132 (self warn:'SourceCodeManagement is disabled or not configured.\\Please setup in the Launcher.' withCRs) ifFalse:[ |
133 |
|
134 packageUpdater := [ |
|
135 |theModulePrefix| |
|
136 |
|
137 theModulePrefix := moduleHolder value , ':'. |
|
138 |
|
139 Cursor wait showWhile:[ |
|
140 knownPackages := Set new. |
|
141 Smalltalk allClassesDo:[:cls | |pckg idx| |
|
142 pckg := cls package. |
|
143 pckg size > 0 ifTrue:[ |
|
144 (pckg startsWith:theModulePrefix) ifTrue:[ |
|
145 idx := pckg indexOf:$:. |
|
146 knownPackages add:(pckg copyFrom:idx + 1) |
|
147 ] |
|
148 ] |
|
149 ]. |
|
150 knownPackages := knownPackages asOrderedCollection. |
|
151 knownPackages := knownPackages select:[:package | package isBlank not]. |
|
152 knownPackages sort. |
|
153 packageBoxComponent list:knownPackages. |
|
154 ]. |
|
155 ]. |
|
156 |
|
157 fileNameUpdater := [ |
|
158 |module package files| |
|
159 |
|
160 Cursor read showWhile:[ |
|
161 module := moduleHolder value ? '__NoProject__'. |
|
162 package := packageHolder value ? '__NoProject__'. |
|
163 |
|
164 files := SourceCodeManager getExistingContainersInModule:module package:package. |
|
165 files := files asOrderedCollection. |
|
166 files := files select:[:eachFile | eachFile asFilename hasSuffix:'st']. |
|
167 files sort. |
|
168 fileNameBoxComponent list:files. |
|
169 ]. |
|
170 ]. |
|
171 |
|
172 moduleHolder := initialModule asValue. |
|
173 packageHolder := initialPackage asValue. |
|
174 fileNameHolder := initialFileName asValue. |
|
175 |
|
176 resources := ResourcePack for:self. |
|
177 |
|
178 "/ |
|
179 "/ open a dialog for this |
|
180 "/ |
|
181 box := DialogBox new. |
|
182 box label:title. |
|
183 |
|
184 component := box addTextLabel:boxText withCRs. |
|
185 component adjust:#left; borderWidth:0. |
|
186 box addVerticalSpace. |
|
187 box addVerticalSpace. |
|
188 |
|
189 y := box yPosition. |
|
190 component := box addTextLabel:(resources string:'Module:'). |
|
191 component width:0.4; adjust:#right. |
|
192 box yPosition:y. |
|
193 component := box addComboBoxOn:moduleHolder tabable:true. |
|
194 component list:knownContainers. |
|
195 |
|
196 "/ component := box addInputFieldOn:moduleHolder tabable:true. |
|
197 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
198 |
|
199 box addVerticalSpace. |
|
200 y := box yPosition. |
|
201 component := box addTextLabel:(resources string:'Package:'). |
|
202 component width:0.4; adjust:#right. |
|
203 box yPosition:y. |
|
204 packageBoxComponent := component := box addComboBoxOn:packageHolder tabable:true. |
|
205 "/ component := box addInputFieldOn:packageHolder tabable:true. |
|
206 component width:0.6; left:0.4; "immediateAccept:true; "acceptOnLeave:true; cursorMovementWhenUpdating:#beginOfLine. |
|
207 packageUpdater value. |
|
208 moduleHolder onChangeEvaluate:packageUpdater. |
|
209 |
|
210 box addVerticalSpace. |
|
211 y := box yPosition. |
|
212 component := box addTextLabel:(resources string:'Filename:'). |
|
213 component width:0.4; adjust:#right. |
|
214 box yPosition:y. |
|
215 |
|
216 forNewContainer ifTrue:[ |
|
217 component := box addInputFieldOn:fileNameHolder tabable:true. |
|
218 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
219 ] ifFalse:[ |
|
220 fileNameBoxComponent := component := box addComboBoxOn:fileNameHolder tabable:true. |
|
221 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
222 fileNameUpdater value. |
|
223 packageHolder onChangeEvaluate:fileNameUpdater. |
|
224 ]. |
|
225 |
|
226 box addVerticalSpace. |
|
227 |
|
228 notice notNil ifTrue:[ |
|
229 component := box addTextLabel:notice. |
|
230 component adjust:#left; borderWidth:0. |
|
231 ]. |
|
232 |
|
233 box addVerticalSpace. |
|
234 box addAbortAndOkButtons. |
|
235 |
|
236 (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[ |
|
237 component := Button label:'Yes to all'. |
|
238 component action:[ |
|
239 YesToAllNotification queryWith:true. |
|
240 box doAccept. |
|
241 ]. |
|
242 (DialogBox defaultOKButtonAtLeft) ifTrue:[ |
|
243 box addButton:component after:nil. |
|
244 ] ifFalse:[ |
|
245 box addButton:component before:nil. |
|
246 ]. |
|
247 ]. |
|
248 (AbortAllSignal isHandled) ifTrue:[ |
|
249 component := Button label:'Cancel all'. |
|
250 component action:[ |
|
251 box hide. |
|
252 AbortAllSignal raiseSignal. |
|
253 ]. |
|
254 (DialogBox defaultOKButtonAtLeft) ifTrue:[ |
|
255 box addButton:component before:nil. |
|
256 ] ifFalse:[ |
|
257 box addButton:component after:nil. |
|
258 ]. |
|
259 ]. |
|
260 |
|
261 (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[ |
|
262 answer := YesToAllQuery query. |
|
263 ]. |
|
264 |
|
265 answer isNil ifTrue:[ |
|
266 box showAtPointer. |
|
267 answer := box accepted |
|
268 ]. |
|
269 |
|
270 box destroy. |
|
271 answer ifFalse:[ |
|
272 ^ nil |
|
273 ]. |
|
274 |
|
275 module := moduleHolder value withoutSpaces. |
|
276 package := packageHolder value withoutSpaces. |
|
277 fileName := fileNameHolder value withoutSpaces. |
|
278 ^ Dictionary new |
|
279 at:#module put:module; |
|
280 at:#package put:package; |
|
281 at:#fileName put:fileName; |
|
282 yourself |
|
283 |
|
284 " |
|
285 self |
|
286 askForContainer:'enter container' title:'container' note:'some note' |
|
287 initialModule:'foo' initialPackage:'bar' initialFileName:'baz' |
|
288 " |
|
289 ! |
|
290 |
|
291 askForExistingRevision:boxText title:title class:aClass |
|
292 "open a dialog asking for a containers revision; |
|
293 return a revision number, or nil if canceled." |
|
294 |
|
295 |mgr sourceInfo module package fileName| |
|
296 |
|
297 mgr := aClass sourceCodeManager. |
|
298 sourceInfo := mgr sourceInfoOfClass:aClass. |
|
299 sourceInfo isNil ifTrue:[^ nil]. |
|
300 |
|
301 package := mgr packageFromSourceInfo:sourceInfo. |
|
302 module := mgr moduleFromSourceInfo:sourceInfo. |
|
303 fileName := mgr containerFromSourceInfo:sourceInfo. |
|
304 ^ self |
|
305 askForExistingRevision:boxText |
|
306 title:title |
|
307 class:aClass |
|
308 manager:mgr |
|
309 module:module package:package fileName:fileName |
|
310 |
|
311 " |
|
312 SourceCodeManagerUtilities |
|
313 askForRevisionToCompare:'enter revision' |
|
314 title:'revision' |
|
315 class:Array |
|
316 " |
|
317 ! |
|
318 |
|
319 askForExistingRevision:boxText title:title class:clsOrNil manager:aSourceCodeManager module:module package:package fileName:fileName |
|
320 "open a dialog asking for a containers revision; |
|
321 return a revision number, or nil if canceled." |
|
322 |
|
323 |partialLog revisions items newestRev |
|
324 box y component resources |
|
325 revisionHolder| |
|
326 |
|
327 partialLog := aSourceCodeManager |
|
328 revisionLogOf:clsOrNil |
|
329 numberOfRevisions:20 |
|
330 fileName:fileName |
|
331 directory:package |
|
332 module:module. |
|
333 partialLog notNil ifTrue:[ |
|
334 newestRev := partialLog at:#newestRevision. |
|
335 revisions := partialLog at:#revisions. |
|
336 items := revisions collect:[:each | |rev date who| |
|
337 rev := each at:#revision. |
|
338 date := each at:#date. |
|
339 who := each at:#author. |
|
340 rev allBold , ' [' , date , ' by ' , who , ']' |
|
341 ]. |
|
342 revisions := revisions collect:[:each | each at:#revision]. |
|
343 ] ifFalse:[ |
|
344 newestRev := aSourceCodeManager newestRevisionInFile:fileName directory:package module:module. |
|
345 revisions := items := nil. |
|
346 |
|
347 newestRev isNil ifTrue:[ |
|
348 (aSourceCodeManager checkForExistingContainerInModule:module package:package container:fileName) |
|
349 ifFalse:[ |
|
350 self warn:'Could not find/access the container for ',fileName,' in the repository. |
|
351 This could be due to: |
|
352 - invalid/wrong CVS-Root setting |
|
353 - missing CVS access rights |
|
354 (no access / not logged in) |
|
355 - changed CVSRoot after compilation |
|
356 (i.e. wrong CVS-path in classes version method) |
|
357 '. |
|
358 ^ nil |
133 ^ nil |
359 ] |
134 ]. |
360 ] |
135 ]. |
361 ]. |
136 (self confirm:'Class does not seem to provide a valid sourceCodeManager.\\Assume CVS ?' withCRs) ifFalse:[ |
362 revisionHolder := newestRev asValue. |
137 ^ nil |
363 resources := ResourcePack for:self. |
138 ]. |
364 |
139 mgr := CVSSourceCodeManager. |
365 revisionHolder onChangeEvaluate:[ |
140 ]. |
366 "/ cut off everything after revision |
141 ^ mgr |
367 |s first words| |
142 ! ! |
368 |
143 |
369 s := revisionHolder value. |
144 !SourceCodeManagerUtilities class methodsFor:'utilities-cvs'! |
370 words := s asCollectionOfWords. |
|
371 words size > 0 ifTrue:[ |
|
372 first := words first string. |
|
373 first ~= s ifTrue:[ |
|
374 revisionHolder value:first |
|
375 ] |
|
376 ] |
|
377 ]. |
|
378 |
|
379 "/ |
|
380 "/ open a dialog for this |
|
381 "/ |
|
382 box := DialogBox new. |
|
383 box label:title. |
|
384 |
|
385 component := box addTextLabel:boxText withCRs. |
|
386 component adjust:#left; borderWidth:0. |
|
387 box addVerticalSpace. |
|
388 box addVerticalSpace. |
|
389 |
|
390 y := box yPosition. |
|
391 component := box addTextLabel:(resources string:'Revision:'). |
|
392 component width:0.4; adjust:#right. |
|
393 box yPosition:y. |
|
394 component := box addComboBoxOn:revisionHolder tabable:true. |
|
395 component list:items. |
|
396 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
397 |
|
398 box addVerticalSpace. |
|
399 |
|
400 box addAbortAndOkButtons. |
|
401 |
|
402 Object abortAllSignal isHandled ifTrue:[ |
|
403 (box addAbortButtonLabelled:'Cancel all') action:[AbortAllSignal raise]. |
|
404 ]. |
|
405 |
|
406 box showAtPointer. |
|
407 |
|
408 box accepted ifFalse:[ |
|
409 box destroy. |
|
410 ^ nil |
|
411 ]. |
|
412 box destroy. |
|
413 |
|
414 ^ revisionHolder value withoutSpaces. |
|
415 |
|
416 " |
|
417 SourceCodeManagerUtilities |
|
418 askForRevisionToCompare:'enter revision' |
|
419 title:'revision' |
|
420 class:nil |
|
421 manager:SourceCodeManager |
|
422 module:'stx' |
|
423 package:'libbasic' |
|
424 fileName:'Array.st' |
|
425 " |
|
426 ! |
|
427 |
|
428 checkAndWarnAboutBadMessagesInClass:aClass |
|
429 "check if a class contains message-sends to: |
|
430 #halt |
|
431 #halt: |
|
432 #error |
|
433 (and maybe more in the future)" |
|
434 |
|
435 |badStuff whatIsBad msg answer labels values| |
|
436 |
|
437 badStuff := #( |
|
438 ( #halt 'sent of #halt (use for debugging only) - better use #error:''some message''' ) |
|
439 ( #halt: 'sent of #halt: (use for debugging only) - better use #error:' ) |
|
440 ( #error 'sent of #error without descriptive message - better use #error:''some message''' ) |
|
441 ). |
|
442 |
|
443 whatIsBad := Set new. |
|
444 aClass theNonMetaclass instAndClassSelectorsAndMethodsDo:[:sel :mthd | |
|
445 |setOfLiterals setOfSentMessages| |
|
446 |
|
447 setOfLiterals := mthd literals. "/ try without parsing first. |
|
448 (badStuff contains:[:eachEntry | setOfLiterals includes:eachEntry first]) ifTrue:[ |
|
449 setOfSentMessages := mthd messagesSent. |
|
450 badStuff do:[:eachEntry | |
|
451 (setOfSentMessages includes:eachEntry first) ifTrue:[ |
|
452 whatIsBad add:eachEntry second |
|
453 ] |
|
454 ]. |
|
455 ]. |
|
456 ]. |
|
457 whatIsBad notEmpty ifTrue:[ |
|
458 (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[ |
|
459 answer := YesToAllQuery query. |
|
460 answer notNil ifTrue:[ ^ answer ]. |
|
461 ]. |
|
462 |
|
463 msg := '%1 contains the following (considered bad style) message sends:\\'. |
|
464 whatIsBad do:[:each | |
|
465 msg := msg , ' ' , each , '\' |
|
466 ]. |
|
467 msg := msg , '\\' , 'Do you really want to checkIn the %1 class ?'. |
|
468 msg := msg bindWith:aClass name. |
|
469 (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[ |
|
470 labels := #('Yes' 'Yes to all' 'No' 'No to all' 'Cancel'). |
|
471 values := #(true #yesToAll false #noToAll nil). |
|
472 AbortAllSignal isHandled ifTrue:[ |
|
473 labels := labels , #('Cancel All'). |
|
474 values := values , #(#cancelAll). |
|
475 ]. |
|
476 answer := OptionBox |
|
477 request:msg withCRs |
|
478 label:'Really checkIn ?' |
|
479 form:(InfoBox iconBitmap) |
|
480 buttonLabels:labels |
|
481 values:values |
|
482 default:#yesToAll |
|
483 onCancel:nil. |
|
484 answer isNil ifTrue:[ |
|
485 AbortSignal raise. |
|
486 ]. |
|
487 answer == #cancelAll ifTrue:[ |
|
488 AbortAllSignal raise. |
|
489 ]. |
|
490 |
|
491 answer == #yesToAll ifTrue:[ |
|
492 YesToAllNotification queryWith:true. |
|
493 ^ true |
|
494 ]. |
|
495 answer == #noToAll ifTrue:[ |
|
496 YesToAllNotification queryWith:false. |
|
497 ^ false |
|
498 ]. |
|
499 ^ answer |
|
500 ] ifFalse:[ |
|
501 ^ self confirm:msg withCRs |
|
502 ] |
|
503 ]. |
|
504 ^ true. |
|
505 |
|
506 " |
|
507 self checkAndWarnAboutBadMessagesInClass:(SourceCodeManagerUtilities) |
|
508 " |
|
509 ! |
|
510 |
145 |
511 checkForExistingModule:module package:package container:containerFileName using:mgr allowCreate:allowCreate |
146 checkForExistingModule:module package:package container:containerFileName using:mgr allowCreate:allowCreate |
512 |resources moduleName packageName containerName| |
147 |resources moduleName packageName containerName| |
513 |
148 |
514 resources := ResourcePack for:self. |
149 resources := ResourcePack for:self. |
1728 ^ false. |
1363 ^ false. |
1729 ]. |
1364 ]. |
1730 ^ true |
1365 ^ true |
1731 ! |
1366 ! |
1732 |
1367 |
1733 getLogMessageFor:aString |
|
1734 "get a log message for checking in a class. |
|
1735 Return the message or nil if aborted." |
|
1736 |
|
1737 ^ self getLogMessageFor:aString initialAnswer:LastSourceLogMessage |
|
1738 |
|
1739 " |
|
1740 SourceCodeManagerUtilities getLogMessageFor:'hello' |
|
1741 " |
|
1742 ! |
|
1743 |
|
1744 getLogMessageFor:aString initialAnswer:initialAnswer |
|
1745 "get a log message for checking in a class. |
|
1746 Return the message or nil if aborted." |
|
1747 |
|
1748 |resources logMsg| |
|
1749 |
|
1750 resources := ResourcePack for:self. |
|
1751 logMsg := Dialog |
|
1752 requestText:(resources string:'Enter log message for: %1' with:aString allBold) |
|
1753 lines:10 |
|
1754 columns:70 |
|
1755 initialAnswer:(initialAnswer ? LastSourceLogMessage ? ''). |
|
1756 |
|
1757 logMsg notNil ifTrue:[ |
|
1758 LastSourceLogMessage := logMsg |
|
1759 ]. |
|
1760 ^ logMsg |
|
1761 |
|
1762 " |
|
1763 SourceCodeManagerUtilities getLogMessageFor:'hello' |
|
1764 " |
|
1765 ! |
|
1766 |
|
1767 getLogMessageFor:aString withButton:additionalButton |
|
1768 "get a log message for checking in a class. |
|
1769 Return the message or nil if aborted." |
|
1770 |
|
1771 |resources logMsg dialog textHolder| |
|
1772 |
|
1773 resources := ResourcePack for:self. |
|
1774 textHolder := '' asValue. |
|
1775 dialog := Dialog |
|
1776 forRequestText:(resources string:'enter log message for: %1' with:aString) |
|
1777 lines:10 |
|
1778 columns:70 |
|
1779 initialAnswer:LastSourceLogMessage |
|
1780 model:textHolder. |
|
1781 |
|
1782 additionalButton notNil ifTrue:[ |
|
1783 dialog addButton:additionalButton before:(dialog okButton). |
|
1784 ]. |
|
1785 |
|
1786 dialog open. |
|
1787 dialog accepted ifFalse:[ |
|
1788 ^ nil. |
|
1789 ]. |
|
1790 logMsg := textHolder value. |
|
1791 "/ logMsg := Dialog |
|
1792 "/ requestText:(resources string:'enter log message for: %1' with:aString) |
|
1793 "/ lines:10 |
|
1794 "/ columns:70 |
|
1795 "/ initialAnswer:LastSourceLogMessage. |
|
1796 logMsg notNil ifTrue:[ |
|
1797 LastSourceLogMessage := logMsg |
|
1798 ]. |
|
1799 ^ logMsg |
|
1800 |
|
1801 " |
|
1802 SourceCodeManagerUtilities getLogMessageFor:'hello' |
|
1803 SourceCodeManagerUtilities getLogMessageFor:'hello' withButton:(Button label:'foo') |
|
1804 " |
|
1805 ! |
|
1806 |
|
1807 getMethodVersionsOfClass:aClass selector:selector numberOfRevisions:numberOfRevisionsOrNil |
|
1808 "check-out all previous versions of aClass and retrieve the history of selector. |
|
1809 Return a dictionary associating revision with a changeList entries for that method. |
|
1810 Unfinished - need a GUI for that." |
|
1811 |
|
1812 |mgr theClass revisionLog revisions items s entriesPerRevision previousVersion| |
|
1813 |
|
1814 theClass := aClass theNonMetaclass. |
|
1815 |
|
1816 mgr := self sourceCodeManagerFor:theClass. |
|
1817 mgr isNil ifTrue:[ |
|
1818 self error:'no sourceCodeManager'. |
|
1819 ]. |
|
1820 |
|
1821 revisionLog := mgr |
|
1822 revisionLogOf:theClass |
|
1823 numberOfRevisions:numberOfRevisionsOrNil. |
|
1824 |
|
1825 revisions := revisionLog at:#revisions. |
|
1826 items := revisions collect:[:each | |rev date who| |
|
1827 rev := each at:#revision. |
|
1828 date := each at:#date. |
|
1829 who := each at:#author. |
|
1830 rev allBold , ' [' , date , ' by ' , who , ']' |
|
1831 ]. |
|
1832 |
|
1833 revisions := revisions collect:[:each | each at:#revision]. |
|
1834 revisions addFirst:#current. |
|
1835 entriesPerRevision := Dictionary new. |
|
1836 |
|
1837 previousVersion := nil. |
|
1838 revisions reverseDo:[:eachRevision | |
|
1839 |srcStream entries thisVersion| |
|
1840 |
|
1841 eachRevision == #current ifTrue:[ |
|
1842 s := '' writeStream. |
|
1843 theClass fileOutOn:s withTimeStamp:false. |
|
1844 srcStream := s contents readStream. |
|
1845 ] ifFalse:[ |
|
1846 self activityNotification:('checking out revision ' , eachRevision , '...'). |
|
1847 srcStream := mgr getSourceStreamFor:theClass revision:eachRevision. |
|
1848 ]. |
|
1849 |
|
1850 entries := ChangeSet fromStream:srcStream. |
|
1851 srcStream close. |
|
1852 |
|
1853 "/ remove all definitions |
|
1854 entries := entries select:[:each | each isMethodChange]. |
|
1855 "/ remove all methods which are for other selectors |
|
1856 entries := entries select:[:each | each selector == selector]. |
|
1857 "/ remove all methods which are for private subclasses |
|
1858 entries := entries select:[:each | each className = aClass name]. |
|
1859 |
|
1860 entries size == 1 ifTrue:[ |
|
1861 "/ the method is there |
|
1862 thisVersion := entries first. |
|
1863 (previousVersion notNil and:[previousVersion sameAs:thisVersion]) ifTrue:[ |
|
1864 "/ no change |
|
1865 ] ifFalse:[ |
|
1866 entriesPerRevision at:eachRevision put:thisVersion. |
|
1867 ]. |
|
1868 ] ifFalse:[ |
|
1869 "/ the method is not there |
|
1870 ]. |
|
1871 previousVersion := thisVersion. |
|
1872 ]. |
|
1873 self error:'unfinished code'. |
|
1874 |
|
1875 " |
|
1876 self getMethodVersionsOfClass:MenuPanel selector:#'helpTextForItem:' numberOfRevisions:20 |
|
1877 self getMethodVersionsOfClass:NewLauncher class selector:#'menu' numberOfRevisions:20 |
|
1878 " |
|
1879 ! |
|
1880 |
|
1881 guessEncodingOfBuffer:buffer |
|
1882 "look for a string of the form |
|
1883 encoding #name |
|
1884 or: |
|
1885 encoding: name |
|
1886 within the given buffer |
|
1887 (which is usually the first few bytes of a textFile)." |
|
1888 |
|
1889 |s idx w withoutQuotes lcBuffer enc| |
|
1890 |
|
1891 withoutQuotes := |
|
1892 [ |
|
1893 ((w startsWith:$") or:[(w startsWith:$')]) ifTrue:[ |
|
1894 w := w copyFrom:2 |
|
1895 ]. |
|
1896 ((w endsWith:$") or:[(w endsWith:$')]) ifTrue:[ |
|
1897 w := w copyWithoutLast:1 |
|
1898 ]. |
|
1899 w |
|
1900 ]. |
|
1901 |
|
1902 lcBuffer := buffer asLowercase. |
|
1903 |
|
1904 #( 'charset' 'encoding' ) do:[:keyWord | |
|
1905 (idx := lcBuffer findString:keyWord) ~~ 0 ifTrue:[ |
|
1906 s := ReadStream on:buffer. |
|
1907 s position1Based:idx. |
|
1908 s skip:keyWord size. |
|
1909 s skipSeparators. |
|
1910 |
|
1911 ['=:#' includes:s peek] whileTrue:[ |
|
1912 s next. |
|
1913 s skipSeparators. |
|
1914 ]. |
|
1915 s skipSeparators. |
|
1916 w := s upToSeparator. |
|
1917 w notNil ifTrue:[ |
|
1918 enc := withoutQuotes value. |
|
1919 (CharacterEncoder encoderFor:enc ifAbsent:nil) notNil ifTrue:[ |
|
1920 ^ enc asSymbol |
|
1921 ]. |
|
1922 enc size >=3 ifTrue:[ |
|
1923 Transcript showCR:'Unknown encoding: ' , withoutQuotes value. |
|
1924 ] |
|
1925 ]. |
|
1926 ]. |
|
1927 ]. |
|
1928 ^ nil |
|
1929 ! |
|
1930 |
|
1931 guessEncodingOfFile:aFilename |
|
1932 "look for a string |
|
1933 encoding #name |
|
1934 or: |
|
1935 encoding: name |
|
1936 within the given buffer |
|
1937 (which is usually the first few bytes of a textFile). |
|
1938 If thats not found, use heuristics (in CharacterArray) to guess." |
|
1939 |
|
1940 |s buffer n "{Class: SmallInteger }" |
|
1941 binary enc| |
|
1942 |
|
1943 s := aFilename asFilename readStreamOrNil. |
|
1944 s isNil ifTrue:[^ nil]. |
|
1945 |
|
1946 buffer := String new:2048. |
|
1947 n := buffer size. |
|
1948 n := s nextBytes:n into:buffer. |
|
1949 s close. |
|
1950 |
|
1951 enc := self guessEncodingOfBuffer:buffer. |
|
1952 enc notNil ifTrue:[^ enc]. |
|
1953 |
|
1954 binary := false. |
|
1955 1 to:n do:[:i | |
|
1956 (buffer at:i) isPrintable ifFalse:[binary := true]. |
|
1957 ]. |
|
1958 |
|
1959 "/ look for JIS7 / EUC encoding |
|
1960 (buffer findString:(CharacterEncoder jisISO2022EscapeSequence)) ~~ 0 ifTrue:[ |
|
1961 ^ #'iso2020-jp' |
|
1962 ]. |
|
1963 (buffer findString:(CharacterEncoder jis7KanjiEscapeSequence)) ~~ 0 ifTrue:[ |
|
1964 ^ #jis7 |
|
1965 ]. |
|
1966 (buffer findString:(CharacterEncoder jis7KanjiOldEscapeSequence)) ~~ 0 ifTrue:[ |
|
1967 ^ #jis7 |
|
1968 ]. |
|
1969 |
|
1970 "/ TODO: |
|
1971 |
|
1972 "/ "/ look for EUC |
|
1973 "/ idx := aString findFirst:[:char | |ascii| |
|
1974 "/ ((ascii := char asciiValue) >= 16rA1) |
|
1975 "/ and:[ascii <= 16rFE]]. |
|
1976 "/ idx ~~ 0 ifTrue:[ |
|
1977 "/ ascii := (aString at:(idx + 1)) asciiValue. |
|
1978 "/ (ascii >= 16rA1 and:[ascii <= 16rFE]) ifTrue:[ |
|
1979 "/ ^ #euc |
|
1980 "/ ] |
|
1981 "/ ]. |
|
1982 "/ look for SJIS ... |
|
1983 |
|
1984 ^ nil |
|
1985 |
|
1986 " |
|
1987 SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_de.rs' asFilename |
|
1988 SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_ru.rs' asFilename |
|
1989 " |
|
1990 ! |
|
1991 |
|
1992 guessEncodingOfStream:aStream |
|
1993 "look for a string of the form |
|
1994 encoding #name |
|
1995 or: |
|
1996 encoding: name |
|
1997 in the first few bytes of aStream." |
|
1998 |
|
1999 |oldPosition buffer n| |
|
2000 |
|
2001 buffer := String new:2048. |
|
2002 |
|
2003 oldPosition := aStream position. |
|
2004 n := buffer size. |
|
2005 n := aStream nextBytes:n into:buffer. |
|
2006 aStream position:oldPosition. |
|
2007 |
|
2008 ^ self guessEncodingOfBuffer:buffer |
|
2009 ! |
|
2010 |
|
2011 removeSourceContainerForClass:aClass |
1368 removeSourceContainerForClass:aClass |
2012 "show container & let user confirm twice." |
1369 "show container & let user confirm twice." |
2013 |
1370 |
2014 ^ self removeSourceContainerForClass:aClass confirm:true warn:true |
1371 ^ self removeSourceContainerForClass:aClass confirm:true warn:true |
2015 ! |
1372 ! |
2187 msg notNil ifTrue:[ |
1544 msg notNil ifTrue:[ |
2188 aStream cr; nextPutAll:msg. |
1545 aStream cr; nextPutAll:msg. |
2189 ] |
1546 ] |
2190 ] |
1547 ] |
2191 ] |
1548 ] |
2192 ! |
1549 ! ! |
2193 |
1550 |
2194 setPackageOfAllMethodsIn:aClass to:aPackage |
1551 !SourceCodeManagerUtilities class methodsFor:'utilities-cvs-helpers'! |
2195 "make all methods belong to the classes project" |
1552 |
2196 |
1553 getLogMessageFor:aString |
2197 |anyChange anyChangeHere| |
1554 "get a log message for checking in a class. |
2198 |
1555 Return the message or nil if aborted." |
2199 anyChange := false. |
1556 |
2200 aClass withAllPrivateClassesDo:[:eachClass | |
1557 ^ self getLogMessageFor:aString initialAnswer:LastSourceLogMessage |
2201 anyChangeHere := false. |
1558 |
2202 eachClass instAndClassSelectorsAndMethodsDo:[:sel :mthd | |
1559 " |
2203 mthd package ~= aPackage ifTrue:[ |
1560 SourceCodeManagerUtilities getLogMessageFor:'hello' |
2204 mthd setPackage:aPackage. |
1561 " |
2205 anyChangeHere := true. |
1562 ! |
2206 ]. |
1563 |
2207 ]. |
1564 getLogMessageFor:aString initialAnswer:initialAnswer |
2208 anyChangeHere ifTrue:[ |
1565 "get a log message for checking in a class. |
2209 eachClass changed:#projectOrganization |
1566 Return the message or nil if aborted." |
2210 ]. |
1567 |
2211 anyChangeHere ifTrue:[anyChange := true]. |
1568 |resources logMsg| |
2212 ]. |
1569 |
2213 anyChange ifTrue:[ |
1570 resources := ResourcePack for:self. |
2214 Smalltalk changed:#projectOrganization |
1571 logMsg := Dialog |
2215 ]. |
1572 requestText:(resources string:'Enter log message for: %1' with:aString allBold) |
2216 ^ anyChange |
1573 lines:10 |
2217 ! |
1574 columns:70 |
2218 |
1575 initialAnswer:(initialAnswer ? LastSourceLogMessage ? ''). |
2219 sourceCodeManagerFor:aClass |
1576 |
2220 |mgr| |
1577 logMsg notNil ifTrue:[ |
2221 |
1578 LastSourceLogMessage := logMsg |
2222 mgr := (aClass sourceCodeManager). |
1579 ]. |
|
1580 ^ logMsg |
|
1581 |
|
1582 " |
|
1583 SourceCodeManagerUtilities getLogMessageFor:'hello' |
|
1584 " |
|
1585 ! |
|
1586 |
|
1587 getLogMessageFor:aString withButton:additionalButton |
|
1588 "get a log message for checking in a class. |
|
1589 Return the message or nil if aborted." |
|
1590 |
|
1591 |resources logMsg dialog textHolder| |
|
1592 |
|
1593 resources := ResourcePack for:self. |
|
1594 textHolder := '' asValue. |
|
1595 dialog := Dialog |
|
1596 forRequestText:(resources string:'enter log message for: %1' with:aString) |
|
1597 lines:10 |
|
1598 columns:70 |
|
1599 initialAnswer:LastSourceLogMessage |
|
1600 model:textHolder. |
|
1601 |
|
1602 additionalButton notNil ifTrue:[ |
|
1603 dialog addButton:additionalButton before:(dialog okButton). |
|
1604 ]. |
|
1605 |
|
1606 dialog open. |
|
1607 dialog accepted ifFalse:[ |
|
1608 ^ nil. |
|
1609 ]. |
|
1610 logMsg := textHolder value. |
|
1611 "/ logMsg := Dialog |
|
1612 "/ requestText:(resources string:'enter log message for: %1' with:aString) |
|
1613 "/ lines:10 |
|
1614 "/ columns:70 |
|
1615 "/ initialAnswer:LastSourceLogMessage. |
|
1616 logMsg notNil ifTrue:[ |
|
1617 LastSourceLogMessage := logMsg |
|
1618 ]. |
|
1619 ^ logMsg |
|
1620 |
|
1621 " |
|
1622 SourceCodeManagerUtilities getLogMessageFor:'hello' |
|
1623 SourceCodeManagerUtilities getLogMessageFor:'hello' withButton:(Button label:'foo') |
|
1624 " |
|
1625 ! |
|
1626 |
|
1627 getMethodVersionsOfClass:aClass selector:selector numberOfRevisions:numberOfRevisionsOrNil |
|
1628 "check-out all previous versions of aClass and retrieve the history of selector. |
|
1629 Return a dictionary associating revision with a changeList entries for that method. |
|
1630 Unfinished - need a GUI for that." |
|
1631 |
|
1632 |mgr theClass revisionLog revisions items s entriesPerRevision previousVersion| |
|
1633 |
|
1634 theClass := aClass theNonMetaclass. |
|
1635 |
|
1636 mgr := self sourceCodeManagerFor:theClass. |
2223 mgr isNil ifTrue:[ |
1637 mgr isNil ifTrue:[ |
2224 SourceCodeManager isNil ifTrue:[ |
1638 self error:'no sourceCodeManager'. |
2225 (self warn:'SourceCodeManagement is disabled or not configured.\\Please setup in the Launcher.' withCRs) ifFalse:[ |
1639 ]. |
|
1640 |
|
1641 revisionLog := mgr |
|
1642 revisionLogOf:theClass |
|
1643 numberOfRevisions:numberOfRevisionsOrNil. |
|
1644 |
|
1645 revisions := revisionLog at:#revisions. |
|
1646 items := revisions collect:[:each | |rev date who| |
|
1647 rev := each at:#revision. |
|
1648 date := each at:#date. |
|
1649 who := each at:#author. |
|
1650 rev allBold , ' [' , date , ' by ' , who , ']' |
|
1651 ]. |
|
1652 |
|
1653 revisions := revisions collect:[:each | each at:#revision]. |
|
1654 revisions addFirst:#current. |
|
1655 entriesPerRevision := Dictionary new. |
|
1656 |
|
1657 previousVersion := nil. |
|
1658 revisions reverseDo:[:eachRevision | |
|
1659 |srcStream entries thisVersion| |
|
1660 |
|
1661 eachRevision == #current ifTrue:[ |
|
1662 s := '' writeStream. |
|
1663 theClass fileOutOn:s withTimeStamp:false. |
|
1664 srcStream := s contents readStream. |
|
1665 ] ifFalse:[ |
|
1666 self activityNotification:('checking out revision ' , eachRevision , '...'). |
|
1667 srcStream := mgr getSourceStreamFor:theClass revision:eachRevision. |
|
1668 ]. |
|
1669 |
|
1670 entries := ChangeSet fromStream:srcStream. |
|
1671 srcStream close. |
|
1672 |
|
1673 "/ remove all definitions |
|
1674 entries := entries select:[:each | each isMethodChange]. |
|
1675 "/ remove all methods which are for other selectors |
|
1676 entries := entries select:[:each | each selector == selector]. |
|
1677 "/ remove all methods which are for private subclasses |
|
1678 entries := entries select:[:each | each className = aClass name]. |
|
1679 |
|
1680 entries size == 1 ifTrue:[ |
|
1681 "/ the method is there |
|
1682 thisVersion := entries first. |
|
1683 (previousVersion notNil and:[previousVersion sameAs:thisVersion]) ifTrue:[ |
|
1684 "/ no change |
|
1685 ] ifFalse:[ |
|
1686 entriesPerRevision at:eachRevision put:thisVersion. |
|
1687 ]. |
|
1688 ] ifFalse:[ |
|
1689 "/ the method is not there |
|
1690 ]. |
|
1691 previousVersion := thisVersion. |
|
1692 ]. |
|
1693 self error:'unfinished code'. |
|
1694 |
|
1695 " |
|
1696 self getMethodVersionsOfClass:MenuPanel selector:#'helpTextForItem:' numberOfRevisions:20 |
|
1697 self getMethodVersionsOfClass:NewLauncher class selector:#'menu' numberOfRevisions:20 |
|
1698 " |
|
1699 ! ! |
|
1700 |
|
1701 !SourceCodeManagerUtilities class methodsFor:'utilities-cvs-user interaction'! |
|
1702 |
|
1703 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName |
|
1704 "open a dialog asking for a source container; |
|
1705 return a dictionary containing module, package and filename, |
|
1706 or nil if canceled." |
|
1707 |
|
1708 ^ self |
|
1709 askForContainer:boxText title:title note:notice |
|
1710 initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName |
|
1711 forNewContainer:true |
|
1712 ! |
|
1713 |
|
1714 askForContainer:boxText title:title note:notice initialModule:initialModule initialPackage:initialPackage initialFileName:initialFileName forNewContainer:forNewContainer |
|
1715 "open a dialog asking for a source container; |
|
1716 return a dictionary containing module, package and filename, |
|
1717 or nil if canceled." |
|
1718 |
|
1719 |box y component resources answer |
|
1720 moduleHolder packageHolder fileNameHolder |
|
1721 module package fileName |
|
1722 knownContainers knownPackages packageUpdater |
|
1723 packageBoxComponent fileNameBoxComponent fileNameUpdater| |
|
1724 |
|
1725 knownContainers := Set new. |
|
1726 Smalltalk allClassesDo:[:cls | |pckg| |
|
1727 pckg := cls package. |
|
1728 pckg size > 0 ifTrue:[ |
|
1729 knownContainers add:(pckg upTo:$:) |
|
1730 ] |
|
1731 ]. |
|
1732 knownContainers := knownContainers asOrderedCollection. |
|
1733 knownContainers := knownContainers select:[:module | module isBlank not]. |
|
1734 knownContainers sort. |
|
1735 |
|
1736 packageUpdater := [ |
|
1737 |theModulePrefix| |
|
1738 |
|
1739 theModulePrefix := moduleHolder value , ':'. |
|
1740 |
|
1741 Cursor wait showWhile:[ |
|
1742 knownPackages := Set new. |
|
1743 Smalltalk allClassesDo:[:cls | |pckg idx| |
|
1744 pckg := cls package. |
|
1745 pckg size > 0 ifTrue:[ |
|
1746 (pckg startsWith:theModulePrefix) ifTrue:[ |
|
1747 idx := pckg indexOf:$:. |
|
1748 knownPackages add:(pckg copyFrom:idx + 1) |
|
1749 ] |
|
1750 ] |
|
1751 ]. |
|
1752 knownPackages := knownPackages asOrderedCollection. |
|
1753 knownPackages := knownPackages select:[:package | package isBlank not]. |
|
1754 knownPackages sort. |
|
1755 packageBoxComponent list:knownPackages. |
|
1756 ]. |
|
1757 ]. |
|
1758 |
|
1759 fileNameUpdater := [ |
|
1760 |module package files| |
|
1761 |
|
1762 Cursor read showWhile:[ |
|
1763 module := moduleHolder value ? '__NoProject__'. |
|
1764 package := packageHolder value ? '__NoProject__'. |
|
1765 |
|
1766 files := SourceCodeManager getExistingContainersInModule:module package:package. |
|
1767 files := files asOrderedCollection. |
|
1768 files := files select:[:eachFile | eachFile asFilename hasSuffix:'st']. |
|
1769 files sort. |
|
1770 fileNameBoxComponent list:files. |
|
1771 ]. |
|
1772 ]. |
|
1773 |
|
1774 moduleHolder := initialModule asValue. |
|
1775 packageHolder := initialPackage asValue. |
|
1776 fileNameHolder := initialFileName asValue. |
|
1777 |
|
1778 resources := ResourcePack for:self. |
|
1779 |
|
1780 "/ |
|
1781 "/ open a dialog for this |
|
1782 "/ |
|
1783 box := DialogBox new. |
|
1784 box label:title. |
|
1785 |
|
1786 component := box addTextLabel:boxText withCRs. |
|
1787 component adjust:#left; borderWidth:0. |
|
1788 box addVerticalSpace. |
|
1789 box addVerticalSpace. |
|
1790 |
|
1791 y := box yPosition. |
|
1792 component := box addTextLabel:(resources string:'Module:'). |
|
1793 component width:0.4; adjust:#right. |
|
1794 box yPosition:y. |
|
1795 component := box addComboBoxOn:moduleHolder tabable:true. |
|
1796 component list:knownContainers. |
|
1797 |
|
1798 "/ component := box addInputFieldOn:moduleHolder tabable:true. |
|
1799 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
1800 |
|
1801 box addVerticalSpace. |
|
1802 y := box yPosition. |
|
1803 component := box addTextLabel:(resources string:'Package:'). |
|
1804 component width:0.4; adjust:#right. |
|
1805 box yPosition:y. |
|
1806 packageBoxComponent := component := box addComboBoxOn:packageHolder tabable:true. |
|
1807 "/ component := box addInputFieldOn:packageHolder tabable:true. |
|
1808 component width:0.6; left:0.4; "immediateAccept:true; "acceptOnLeave:true; cursorMovementWhenUpdating:#beginOfLine. |
|
1809 packageUpdater value. |
|
1810 moduleHolder onChangeEvaluate:packageUpdater. |
|
1811 |
|
1812 box addVerticalSpace. |
|
1813 y := box yPosition. |
|
1814 component := box addTextLabel:(resources string:'Filename:'). |
|
1815 component width:0.4; adjust:#right. |
|
1816 box yPosition:y. |
|
1817 |
|
1818 forNewContainer ifTrue:[ |
|
1819 component := box addInputFieldOn:fileNameHolder tabable:true. |
|
1820 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
1821 ] ifFalse:[ |
|
1822 fileNameBoxComponent := component := box addComboBoxOn:fileNameHolder tabable:true. |
|
1823 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
1824 fileNameUpdater value. |
|
1825 packageHolder onChangeEvaluate:fileNameUpdater. |
|
1826 ]. |
|
1827 |
|
1828 box addVerticalSpace. |
|
1829 |
|
1830 notice notNil ifTrue:[ |
|
1831 component := box addTextLabel:notice. |
|
1832 component adjust:#left; borderWidth:0. |
|
1833 ]. |
|
1834 |
|
1835 box addVerticalSpace. |
|
1836 box addAbortAndOkButtons. |
|
1837 |
|
1838 (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[ |
|
1839 component := Button label:'Yes to all'. |
|
1840 component action:[ |
|
1841 YesToAllNotification queryWith:true. |
|
1842 box doAccept. |
|
1843 ]. |
|
1844 (DialogBox defaultOKButtonAtLeft) ifTrue:[ |
|
1845 box addButton:component after:nil. |
|
1846 ] ifFalse:[ |
|
1847 box addButton:component before:nil. |
|
1848 ]. |
|
1849 ]. |
|
1850 (AbortAllSignal isHandled) ifTrue:[ |
|
1851 component := Button label:'Cancel all'. |
|
1852 component action:[ |
|
1853 box hide. |
|
1854 AbortAllSignal raiseSignal. |
|
1855 ]. |
|
1856 (DialogBox defaultOKButtonAtLeft) ifTrue:[ |
|
1857 box addButton:component before:nil. |
|
1858 ] ifFalse:[ |
|
1859 box addButton:component after:nil. |
|
1860 ]. |
|
1861 ]. |
|
1862 |
|
1863 (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[ |
|
1864 answer := YesToAllQuery query. |
|
1865 ]. |
|
1866 |
|
1867 answer isNil ifTrue:[ |
|
1868 box showAtPointer. |
|
1869 answer := box accepted |
|
1870 ]. |
|
1871 |
|
1872 box destroy. |
|
1873 answer ifFalse:[ |
|
1874 ^ nil |
|
1875 ]. |
|
1876 |
|
1877 module := moduleHolder value withoutSpaces. |
|
1878 package := packageHolder value withoutSpaces. |
|
1879 fileName := fileNameHolder value withoutSpaces. |
|
1880 ^ Dictionary new |
|
1881 at:#module put:module; |
|
1882 at:#package put:package; |
|
1883 at:#fileName put:fileName; |
|
1884 yourself |
|
1885 |
|
1886 " |
|
1887 self |
|
1888 askForContainer:'enter container' title:'container' note:'some note' |
|
1889 initialModule:'foo' initialPackage:'bar' initialFileName:'baz' |
|
1890 " |
|
1891 ! |
|
1892 |
|
1893 askForExistingRevision:boxText title:title class:aClass |
|
1894 "open a dialog asking for a containers revision; |
|
1895 return a revision number, or nil if canceled." |
|
1896 |
|
1897 |mgr sourceInfo module package fileName| |
|
1898 |
|
1899 mgr := aClass sourceCodeManager. |
|
1900 sourceInfo := mgr sourceInfoOfClass:aClass. |
|
1901 sourceInfo isNil ifTrue:[^ nil]. |
|
1902 |
|
1903 package := mgr packageFromSourceInfo:sourceInfo. |
|
1904 module := mgr moduleFromSourceInfo:sourceInfo. |
|
1905 fileName := mgr containerFromSourceInfo:sourceInfo. |
|
1906 ^ self |
|
1907 askForExistingRevision:boxText |
|
1908 title:title |
|
1909 class:aClass |
|
1910 manager:mgr |
|
1911 module:module package:package fileName:fileName |
|
1912 |
|
1913 " |
|
1914 SourceCodeManagerUtilities |
|
1915 askForRevisionToCompare:'enter revision' |
|
1916 title:'revision' |
|
1917 class:Array |
|
1918 " |
|
1919 ! |
|
1920 |
|
1921 askForExistingRevision:boxText title:title class:clsOrNil manager:aSourceCodeManager module:module package:package fileName:fileName |
|
1922 "open a dialog asking for a containers revision; |
|
1923 return a revision number, or nil if canceled." |
|
1924 |
|
1925 |partialLog revisions items newestRev |
|
1926 box y component resources |
|
1927 revisionHolder| |
|
1928 |
|
1929 partialLog := aSourceCodeManager |
|
1930 revisionLogOf:clsOrNil |
|
1931 numberOfRevisions:20 |
|
1932 fileName:fileName |
|
1933 directory:package |
|
1934 module:module. |
|
1935 partialLog notNil ifTrue:[ |
|
1936 newestRev := partialLog at:#newestRevision. |
|
1937 revisions := partialLog at:#revisions. |
|
1938 items := revisions collect:[:each | |rev date who| |
|
1939 rev := each at:#revision. |
|
1940 date := each at:#date. |
|
1941 who := each at:#author. |
|
1942 rev allBold , ' [' , date , ' by ' , who , ']' |
|
1943 ]. |
|
1944 revisions := revisions collect:[:each | each at:#revision]. |
|
1945 ] ifFalse:[ |
|
1946 newestRev := aSourceCodeManager newestRevisionInFile:fileName directory:package module:module. |
|
1947 revisions := items := nil. |
|
1948 |
|
1949 newestRev isNil ifTrue:[ |
|
1950 (aSourceCodeManager checkForExistingContainerInModule:module package:package container:fileName) |
|
1951 ifFalse:[ |
|
1952 self warn:'Could not find/access the container for ',fileName,' in the repository. |
|
1953 This could be due to: |
|
1954 - invalid/wrong CVS-Root setting |
|
1955 - missing CVS access rights |
|
1956 (no access / not logged in) |
|
1957 - changed CVSRoot after compilation |
|
1958 (i.e. wrong CVS-path in classes version method) |
|
1959 '. |
2226 ^ nil |
1960 ^ nil |
2227 ]. |
1961 ] |
2228 ]. |
1962 ] |
2229 (self confirm:'Class does not seem to provide a valid sourceCodeManager.\\Assume CVS ?' withCRs) ifFalse:[ |
1963 ]. |
2230 ^ nil |
1964 revisionHolder := newestRev asValue. |
2231 ]. |
1965 resources := ResourcePack for:self. |
2232 mgr := CVSSourceCodeManager. |
1966 |
2233 ]. |
1967 revisionHolder onChangeEvaluate:[ |
2234 ^ mgr |
1968 "/ cut off everything after revision |
|
1969 |s first words| |
|
1970 |
|
1971 s := revisionHolder value. |
|
1972 words := s asCollectionOfWords. |
|
1973 words size > 0 ifTrue:[ |
|
1974 first := words first string. |
|
1975 first ~= s ifTrue:[ |
|
1976 revisionHolder value:first |
|
1977 ] |
|
1978 ] |
|
1979 ]. |
|
1980 |
|
1981 "/ |
|
1982 "/ open a dialog for this |
|
1983 "/ |
|
1984 box := DialogBox new. |
|
1985 box label:title. |
|
1986 |
|
1987 component := box addTextLabel:boxText withCRs. |
|
1988 component adjust:#left; borderWidth:0. |
|
1989 box addVerticalSpace. |
|
1990 box addVerticalSpace. |
|
1991 |
|
1992 y := box yPosition. |
|
1993 component := box addTextLabel:(resources string:'Revision:'). |
|
1994 component width:0.4; adjust:#right. |
|
1995 box yPosition:y. |
|
1996 component := box addComboBoxOn:revisionHolder tabable:true. |
|
1997 component list:items. |
|
1998 component width:0.6; left:0.4; immediateAccept:true; acceptOnLeave:false; cursorMovementWhenUpdating:#beginOfLine. |
|
1999 |
|
2000 box addVerticalSpace. |
|
2001 |
|
2002 box addAbortAndOkButtons. |
|
2003 |
|
2004 Object abortAllSignal isHandled ifTrue:[ |
|
2005 (box addAbortButtonLabelled:'Cancel all') action:[AbortAllSignal raise]. |
|
2006 ]. |
|
2007 |
|
2008 box showAtPointer. |
|
2009 |
|
2010 box accepted ifFalse:[ |
|
2011 box destroy. |
|
2012 ^ nil |
|
2013 ]. |
|
2014 box destroy. |
|
2015 |
|
2016 ^ revisionHolder value withoutSpaces. |
|
2017 |
|
2018 " |
|
2019 SourceCodeManagerUtilities |
|
2020 askForRevisionToCompare:'enter revision' |
|
2021 title:'revision' |
|
2022 class:nil |
|
2023 manager:SourceCodeManager |
|
2024 module:'stx' |
|
2025 package:'libbasic' |
|
2026 fileName:'Array.st' |
|
2027 " |
|
2028 ! |
|
2029 |
|
2030 checkAndWarnAboutBadMessagesInClass:aClass |
|
2031 "check if a class contains message-sends to: |
|
2032 #halt |
|
2033 #halt: |
|
2034 #error |
|
2035 (and maybe more in the future)" |
|
2036 |
|
2037 |badStuff whatIsBad msg answer labels values| |
|
2038 |
|
2039 badStuff := #( |
|
2040 ( #halt 'sent of #halt (use for debugging only) - better use #error:''some message''' ) |
|
2041 ( #halt: 'sent of #halt: (use for debugging only) - better use #error:' ) |
|
2042 ( #error 'sent of #error without descriptive message - better use #error:''some message''' ) |
|
2043 ). |
|
2044 |
|
2045 whatIsBad := Set new. |
|
2046 aClass theNonMetaclass instAndClassSelectorsAndMethodsDo:[:sel :mthd | |
|
2047 |setOfLiterals setOfSentMessages| |
|
2048 |
|
2049 setOfLiterals := mthd literals. "/ try without parsing first. |
|
2050 (badStuff contains:[:eachEntry | setOfLiterals includes:eachEntry first]) ifTrue:[ |
|
2051 setOfSentMessages := mthd messagesSent. |
|
2052 badStuff do:[:eachEntry | |
|
2053 (setOfSentMessages includes:eachEntry first) ifTrue:[ |
|
2054 whatIsBad add:eachEntry second |
|
2055 ] |
|
2056 ]. |
|
2057 ]. |
|
2058 ]. |
|
2059 whatIsBad notEmpty ifTrue:[ |
|
2060 (YesToAllQuery notNil and:[YesToAllQuery isHandled]) ifTrue:[ |
|
2061 answer := YesToAllQuery query. |
|
2062 answer notNil ifTrue:[ ^ answer ]. |
|
2063 ]. |
|
2064 |
|
2065 msg := '%1 contains the following (considered bad style) message sends:\\'. |
|
2066 whatIsBad do:[:each | |
|
2067 msg := msg , ' ' , each , '\' |
|
2068 ]. |
|
2069 msg := msg , '\\' , 'Do you really want to checkIn the %1 class ?'. |
|
2070 msg := msg bindWith:aClass name. |
|
2071 (YesToAllNotification notNil and:[YesToAllNotification isHandled]) ifTrue:[ |
|
2072 labels := #('Yes' 'Yes to all' 'No' 'No to all' 'Cancel'). |
|
2073 values := #(true #yesToAll false #noToAll nil). |
|
2074 AbortAllSignal isHandled ifTrue:[ |
|
2075 labels := labels , #('Cancel All'). |
|
2076 values := values , #(#cancelAll). |
|
2077 ]. |
|
2078 answer := OptionBox |
|
2079 request:msg withCRs |
|
2080 label:'Really checkIn ?' |
|
2081 form:(InfoBox iconBitmap) |
|
2082 buttonLabels:labels |
|
2083 values:values |
|
2084 default:#yesToAll |
|
2085 onCancel:nil. |
|
2086 answer isNil ifTrue:[ |
|
2087 AbortSignal raise. |
|
2088 ]. |
|
2089 answer == #cancelAll ifTrue:[ |
|
2090 AbortAllSignal raise. |
|
2091 ]. |
|
2092 |
|
2093 answer == #yesToAll ifTrue:[ |
|
2094 YesToAllNotification queryWith:true. |
|
2095 ^ true |
|
2096 ]. |
|
2097 answer == #noToAll ifTrue:[ |
|
2098 YesToAllNotification queryWith:false. |
|
2099 ^ false |
|
2100 ]. |
|
2101 ^ answer |
|
2102 ] ifFalse:[ |
|
2103 ^ self confirm:msg withCRs |
|
2104 ] |
|
2105 ]. |
|
2106 ^ true. |
|
2107 |
|
2108 " |
|
2109 self checkAndWarnAboutBadMessagesInClass:(SourceCodeManagerUtilities) |
|
2110 " |
2235 ! ! |
2111 ! ! |
2236 |
2112 |
|
2113 !SourceCodeManagerUtilities class methodsFor:'utilities-encoding'! |
|
2114 |
|
2115 guessEncodingOfBuffer:buffer |
|
2116 "look for a string of the form |
|
2117 encoding #name |
|
2118 or: |
|
2119 encoding: name |
|
2120 within the given buffer |
|
2121 (which is usually the first few bytes of a textFile)." |
|
2122 |
|
2123 |s idx w withoutQuotes lcBuffer enc| |
|
2124 |
|
2125 withoutQuotes := |
|
2126 [ |
|
2127 ((w startsWith:$") or:[(w startsWith:$')]) ifTrue:[ |
|
2128 w := w copyFrom:2 |
|
2129 ]. |
|
2130 ((w endsWith:$") or:[(w endsWith:$')]) ifTrue:[ |
|
2131 w := w copyWithoutLast:1 |
|
2132 ]. |
|
2133 w |
|
2134 ]. |
|
2135 |
|
2136 lcBuffer := buffer asLowercase. |
|
2137 |
|
2138 #( 'charset' 'encoding' ) do:[:keyWord | |
|
2139 (idx := lcBuffer findString:keyWord) ~~ 0 ifTrue:[ |
|
2140 s := ReadStream on:buffer. |
|
2141 s position1Based:idx. |
|
2142 s skip:keyWord size. |
|
2143 s skipSeparators. |
|
2144 |
|
2145 ['=:#' includes:s peek] whileTrue:[ |
|
2146 s next. |
|
2147 s skipSeparators. |
|
2148 ]. |
|
2149 s skipSeparators. |
|
2150 w := s upToSeparator. |
|
2151 w notNil ifTrue:[ |
|
2152 enc := withoutQuotes value. |
|
2153 (CharacterEncoder encoderFor:enc ifAbsent:nil) notNil ifTrue:[ |
|
2154 ^ enc asSymbol |
|
2155 ]. |
|
2156 enc size >=3 ifTrue:[ |
|
2157 Transcript showCR:'Unknown encoding: ' , withoutQuotes value. |
|
2158 ] |
|
2159 ]. |
|
2160 ]. |
|
2161 ]. |
|
2162 ^ nil |
|
2163 ! |
|
2164 |
|
2165 guessEncodingOfFile:aFilename |
|
2166 "look for a string |
|
2167 encoding #name |
|
2168 or: |
|
2169 encoding: name |
|
2170 within the given buffer |
|
2171 (which is usually the first few bytes of a textFile). |
|
2172 If thats not found, use heuristics (in CharacterArray) to guess." |
|
2173 |
|
2174 |s buffer n "{Class: SmallInteger }" |
|
2175 binary enc| |
|
2176 |
|
2177 s := aFilename asFilename readStreamOrNil. |
|
2178 s isNil ifTrue:[^ nil]. |
|
2179 |
|
2180 buffer := String new:2048. |
|
2181 n := buffer size. |
|
2182 n := s nextBytes:n into:buffer. |
|
2183 s close. |
|
2184 |
|
2185 enc := self guessEncodingOfBuffer:buffer. |
|
2186 enc notNil ifTrue:[^ enc]. |
|
2187 |
|
2188 binary := false. |
|
2189 1 to:n do:[:i | |
|
2190 (buffer at:i) isPrintable ifFalse:[binary := true]. |
|
2191 ]. |
|
2192 |
|
2193 "/ look for JIS7 / EUC encoding |
|
2194 (buffer findString:(CharacterEncoder jisISO2022EscapeSequence)) ~~ 0 ifTrue:[ |
|
2195 ^ #'iso2020-jp' |
|
2196 ]. |
|
2197 (buffer findString:(CharacterEncoder jis7KanjiEscapeSequence)) ~~ 0 ifTrue:[ |
|
2198 ^ #jis7 |
|
2199 ]. |
|
2200 (buffer findString:(CharacterEncoder jis7KanjiOldEscapeSequence)) ~~ 0 ifTrue:[ |
|
2201 ^ #jis7 |
|
2202 ]. |
|
2203 |
|
2204 "/ TODO: |
|
2205 |
|
2206 "/ "/ look for EUC |
|
2207 "/ idx := aString findFirst:[:char | |ascii| |
|
2208 "/ ((ascii := char asciiValue) >= 16rA1) |
|
2209 "/ and:[ascii <= 16rFE]]. |
|
2210 "/ idx ~~ 0 ifTrue:[ |
|
2211 "/ ascii := (aString at:(idx + 1)) asciiValue. |
|
2212 "/ (ascii >= 16rA1 and:[ascii <= 16rFE]) ifTrue:[ |
|
2213 "/ ^ #euc |
|
2214 "/ ] |
|
2215 "/ ]. |
|
2216 "/ look for SJIS ... |
|
2217 |
|
2218 ^ nil |
|
2219 |
|
2220 " |
|
2221 SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_de.rs' asFilename |
|
2222 SourceCodeManagerUtilities guessEncodingOfFile:'../../libview2/resources/ApplicationModel_ru.rs' asFilename |
|
2223 " |
|
2224 ! |
|
2225 |
|
2226 guessEncodingOfStream:aStream |
|
2227 "look for a string of the form |
|
2228 encoding #name |
|
2229 or: |
|
2230 encoding: name |
|
2231 in the first few bytes of aStream." |
|
2232 |
|
2233 |oldPosition buffer n| |
|
2234 |
|
2235 buffer := String new:2048. |
|
2236 |
|
2237 oldPosition := aStream position. |
|
2238 n := buffer size. |
|
2239 n := aStream nextBytes:n into:buffer. |
|
2240 aStream position:oldPosition. |
|
2241 |
|
2242 ^ self guessEncodingOfBuffer:buffer |
|
2243 ! ! |
|
2244 |
2237 !SourceCodeManagerUtilities class methodsFor:'documentation'! |
2245 !SourceCodeManagerUtilities class methodsFor:'documentation'! |
2238 |
2246 |
2239 version |
2247 version |
2240 ^ '$Header: /cvs/stx/stx/libbasic3/SourceCodeManagerUtilities.st,v 1.99 2004-03-11 15:39:08 cg Exp $' |
2248 ^ '$Header: /cvs/stx/stx/libbasic3/SourceCodeManagerUtilities.st,v 1.100 2004-03-12 09:36:02 cg Exp $' |
2241 ! ! |
2249 ! ! |