|
1 " |
|
2 COPYRIGHT (c) 2011 by Claus Gittinger |
|
3 All Rights Reserved |
|
4 |
|
5 This software is furnished under a license and may be used |
|
6 only in accordance with the terms of that license and with the |
|
7 inclusion of the above copyright notice. This software may not |
|
8 be provided or otherwise made available to, or used by, any |
|
9 other person. No title to or ownership of the software is |
|
10 hereby transferred. |
|
11 " |
|
12 "{ Package: 'stx:libbasic3' }" |
|
13 |
|
14 AbstractSourceCodeManager subclass:#DataBaseSourceCodeManager |
|
15 instanceVariableNames:'' |
|
16 classVariableNames:'Verbose RepositoryPath ModulePathes' |
|
17 poolDictionaries:'' |
|
18 category:'System-SourceCodeManagement' |
|
19 ! |
|
20 |
|
21 !DataBaseSourceCodeManager class methodsFor:'documentation'! |
|
22 |
|
23 copyright |
|
24 " |
|
25 COPYRIGHT (c) 2011 by Claus Gittinger |
|
26 All Rights Reserved |
|
27 |
|
28 This software is furnished under a license and may be used |
|
29 only in accordance with the terms of that license and with the |
|
30 inclusion of the above copyright notice. This software may not |
|
31 be provided or otherwise made available to, or used by, any |
|
32 other person. No title to or ownership of the software is |
|
33 hereby transferred. |
|
34 " |
|
35 ! |
|
36 |
|
37 documentation |
|
38 " |
|
39 A simple file based sourceCodeManager, which saves versions in a local directory. |
|
40 Versions will be stored as filename.st.vNr (i.e. Foo.st.1, Foo.st.2, etc.) |
|
41 |
|
42 This is more an example of the protocol which needs to be implemented, |
|
43 than a real manager (although it may be useful for tiny private projects or classroom examples) |
|
44 |
|
45 [author:] |
|
46 Claus Gittinger |
|
47 " |
|
48 ! ! |
|
49 |
|
50 !DataBaseSourceCodeManager class methodsFor:'accessing'! |
|
51 |
|
52 getRepositoryPathForModule:aModuleName |
|
53 "internal: used when accessing a source repository. |
|
54 Return the path to the top directory for a particular module. |
|
55 If no specific path was defined for that module, return the value of |
|
56 the global (fallBack) repositoryPath. |
|
57 Nil is returned if no repository is available." |
|
58 |
|
59 ModulePathes isNil ifTrue:[^ RepositoryPath]. |
|
60 aModuleName isNil ifTrue:[^ RepositoryPath]. |
|
61 ^ ModulePathes at:aModuleName ifAbsent:RepositoryPath. |
|
62 |
|
63 "Modified: / 20-05-1998 / 16:30:12 / cg" |
|
64 "Created: / 21-12-2011 / 23:05:51 / cg" |
|
65 ! |
|
66 |
|
67 knownModules |
|
68 "return the modules, we currently know" |
|
69 |
|
70 ^ ModulePathes keys |
|
71 |
|
72 "Modified: / 21-12-2011 / 14:54:53 / cg" |
|
73 ! |
|
74 |
|
75 repositoryPath |
|
76 "return the path of the default repository" |
|
77 |
|
78 ^ RepositoryPath |
|
79 |
|
80 "Created: / 21-12-2011 / 14:55:12 / cg" |
|
81 ! ! |
|
82 |
|
83 !DataBaseSourceCodeManager class methodsFor:'queries'! |
|
84 |
|
85 defaultRepositoryName |
|
86 "/ '<db-type>:[<user>[.<password>]@][<host>]<db-name>[:<table-name>]' |
|
87 |
|
88 ^ 'sqlite:repository.db' |
|
89 |
|
90 "Created: / 22-12-2011 / 00:19:43 / cg" |
|
91 ! |
|
92 |
|
93 enabled |
|
94 ^ true "/ false. |
|
95 |
|
96 "Created: / 21-12-2011 / 17:53:34 / cg" |
|
97 ! |
|
98 |
|
99 isContainerBased |
|
100 "true, if the SCM uses some kind of source container (,v files). |
|
101 False, if it is like a database or filesystem." |
|
102 |
|
103 ^ false |
|
104 |
|
105 "Created: / 21-12-2011 / 18:53:55 / cg" |
|
106 ! |
|
107 |
|
108 isResponsibleForPackage:aString |
|
109 ^ true. |
|
110 |
|
111 "Created: / 09-07-2011 / 14:32:20 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
|
112 "Modified (format): / 22-12-2011 / 00:05:39 / cg" |
|
113 ! |
|
114 |
|
115 managerTypeName |
|
116 ^ 'DBRepository' |
|
117 |
|
118 "Created: / 16-08-2006 / 11:05:56 / cg" |
|
119 ! |
|
120 |
|
121 nameOfVersionMethodForExtensions |
|
122 ^ #'extensionsVersion_DB' |
|
123 |
|
124 "Modified: / 22-12-2011 / 00:06:15 / cg" |
|
125 ! |
|
126 |
|
127 nameOfVersionMethodInClasses |
|
128 ^ #'version_DB' |
|
129 |
|
130 "Modified: / 22-12-2011 / 00:06:21 / cg" |
|
131 ! |
|
132 |
|
133 repositoryNameForPackage:packageId |
|
134 "superclass AbstractSourceCodeManager class says that I am responsible to implement this method" |
|
135 |
|
136 ^ self getDBNameForModule:(packageId upTo:$: ) |
|
137 |
|
138 "Created: / 21-12-2011 / 23:07:02 / cg" |
|
139 ! |
|
140 |
|
141 settingsApplicationClass |
|
142 "link to my settings application (needed for the settings dialog" |
|
143 |
|
144 ^ DataBaseSourceCodeManagementSettingsAppl |
|
145 |
|
146 "Created: / 19-04-2011 / 12:43:29 / cg" |
|
147 "Modified: / 22-12-2011 / 00:06:53 / cg" |
|
148 ! ! |
|
149 |
|
150 !DataBaseSourceCodeManager class methodsFor:'saving'! |
|
151 |
|
152 savePreferencesOn:aStream |
|
153 aStream nextPutLine:'DataBaseSourceCodeManager notNil ifTrue:['. |
|
154 self repositoryInfoPerModule notEmptyOrNil ifTrue:[ |
|
155 aStream nextPutLine:' DataBaseSourceCodeManager repositoryInfoPerModule:' , self repositoryInfoPerModule storeString , '.'. |
|
156 ]. |
|
157 (Smalltalk at:#SourceCodeManager) == self ifTrue:[ |
|
158 aStream nextPutLine:' Smalltalk at:#SourceCodeManager put:DataBaseSourceCodeManager.'. |
|
159 ]. |
|
160 aStream nextPutLine:' DataBaseSourceCodeManager repositoryPath:' , self repositoryPath storeString , '.'. |
|
161 aStream nextPutLine:'].'. |
|
162 |
|
163 "Created: / 09-11-2006 / 15:09:25 / cg" |
|
164 "Modified: / 22-12-2011 / 00:48:25 / cg" |
|
165 ! ! |
|
166 |
|
167 !DataBaseSourceCodeManager class methodsFor:'source code administration'! |
|
168 |
|
169 checkForExistingContainer:fileName inModule:moduleName directory:dirName |
|
170 ^ self checkForExistingModule:moduleName directory:dirName |
|
171 |
|
172 "Created: / 21-12-2011 / 17:56:23 / cg" |
|
173 ! |
|
174 |
|
175 checkForExistingModule:moduleDir |
|
176 "check for a package directory to be present" |
|
177 |
|
178 self halt. |
|
179 "/ |
|
180 "/ dir := self moduleDirectoryFor:moduleDir. |
|
181 "/ ^ dir exists |
|
182 |
|
183 "Created: / 21-12-2011 / 18:37:28 / cg" |
|
184 ! |
|
185 |
|
186 checkForExistingModule:moduleDir directory:packageDir |
|
187 "check for a package directory to be present" |
|
188 |
|
189 self halt. |
|
190 "/ |dir| |
|
191 "/ |
|
192 "/ dir := self packageDirectoryForModule:moduleDir package:packageDir. |
|
193 "/ ^ dir exists |
|
194 "/ |
|
195 "/ |
|
196 |
|
197 "Created: / 21-12-2011 / 18:03:33 / cg" |
|
198 ! |
|
199 |
|
200 checkinClass:aClass fileName:classFileName directory:packageDir module:moduleDir source:sourceFile logMessage:logMessage force:force |
|
201 "Return true if ok, false if not." |
|
202 |
|
203 self halt. |
|
204 "/ |targetDir newestRevision newRevision newFile packageMode filter outStream| |
|
205 "/ |
|
206 "/ targetDir := self packageDirectoryForModule:moduleDir package:packageDir. |
|
207 "/ |
|
208 "/ (targetDir filesMatching:(classFileName,'_*')) do:[:eachVersionFile | |
|
209 "/ |versionString| |
|
210 "/ |
|
211 "/ versionString := eachVersionFile copyFrom:(classFileName size + 2). |
|
212 "/ (newestRevision isNil |
|
213 "/ or:[ self isRevision:versionString after:newestRevision ]) ifTrue:[ |
|
214 "/ newestRevision := versionString |
|
215 "/ ]. |
|
216 "/ ]. |
|
217 "/ |
|
218 "/ newestRevision isNil ifTrue:[ |
|
219 "/ newRevision := '1' |
|
220 "/ ] ifFalse:[ |
|
221 "/ newRevision := self revisionAfter:newestRevision |
|
222 "/ ]. |
|
223 "/ newFile := (targetDir construct:classFileName,'_',newRevision printString). |
|
224 "/ |
|
225 "/ self updateVersionMethodOf:aClass for:(self revisionStringFor:aClass inModule:moduleDir directory:packageDir container:classFileName revision:newRevision). |
|
226 "/ |
|
227 "/ packageMode := self checkMethodPackagesOf:aClass. |
|
228 "/ packageMode == #base ifTrue:[ |
|
229 "/ filter := [:mthd | mthd package = aClass package]. |
|
230 "/ ]. |
|
231 "/ |
|
232 "/ [ |
|
233 "/ outStream := newFile writeStream. |
|
234 "/ ] on:FileStream openErrorSignal do:[:ex| |
|
235 "/ self reportError:('fileout failed'). |
|
236 "/ ^ false |
|
237 "/ ]. |
|
238 "/ |
|
239 "/ Method flushSourceStreamCache. |
|
240 "/ Class fileOutErrorSignal handle:[:ex | |
|
241 "/ outStream close. |
|
242 "/ newFile delete. |
|
243 "/ self reportError:('fileout failed (',ex description,')'). |
|
244 "/ ^ false |
|
245 "/ ] do:[ |
|
246 "/ self |
|
247 "/ fileOutSourceCodeOf:aClass |
|
248 "/ on:outStream |
|
249 "/ withTimeStamp:false |
|
250 "/ withInitialize:true |
|
251 "/ withDefinition:true |
|
252 "/ methodFilter:filter. |
|
253 "/ ]. |
|
254 "/ outStream close. |
|
255 "/ |
|
256 "/ newFile exists ifFalse:[ |
|
257 "/ self reportError:'fileout failed'. |
|
258 "/ ^ false. |
|
259 "/ ]. |
|
260 "/ |
|
261 "/ ^ true |
|
262 "/ |
|
263 "/ |
|
264 |
|
265 "Created: / 21-12-2011 / 19:01:07 / cg" |
|
266 ! |
|
267 |
|
268 createModule:moduleDir |
|
269 "create a module directory" |
|
270 |
|
271 self halt. |
|
272 "/ |dir| |
|
273 "/ |
|
274 "/ dir := self moduleDirectoryFor:moduleDir. |
|
275 "/ dir recursiveMakeDirectory. |
|
276 "/ ^ dir exists. |
|
277 |
|
278 "Created: / 21-12-2011 / 18:38:22 / cg" |
|
279 ! |
|
280 |
|
281 createModule:moduleDir directory:packageDir |
|
282 "create a package directory" |
|
283 |
|
284 self halt. |
|
285 "/ |dir| |
|
286 "/ |
|
287 "/ dir := self packageDirectoryForModule:moduleDir package:packageDir. |
|
288 "/ dir recursiveMakeDirectory. |
|
289 "/ ^ dir exists. |
|
290 |
|
291 "Created: / 21-12-2011 / 18:44:20 / cg" |
|
292 ! |
|
293 |
|
294 initialRevisionStringFor:aClass inModule:moduleDir directory:packageDir container:fileName |
|
295 "return a string usable as initial revision string" |
|
296 |
|
297 ^ self |
|
298 revisionStringFor:aClass |
|
299 inModule:moduleDir |
|
300 directory:packageDir |
|
301 container:fileName |
|
302 revision:'1' |
|
303 |
|
304 "Created: / 21-12-2011 / 18:14:03 / cg" |
|
305 ! |
|
306 |
|
307 moduleDirectoryFor:moduleDir |
|
308 "a modules directory as filename" |
|
309 |
|
310 self halt. |
|
311 "/ |root| |
|
312 "/ |
|
313 "/ root := self getRepositoryPathForModule:moduleDir. |
|
314 "/ root isNil ifTrue:[ |
|
315 "/ RepositoryPath := root := self defaultRepositoryPath. |
|
316 "/ ]. |
|
317 "/ |
|
318 "/ ^ (root asFilename construct:moduleDir) |
|
319 |
|
320 "Created: / 21-12-2011 / 18:38:38 / cg" |
|
321 ! |
|
322 |
|
323 packageDirectoryForModule:moduleDir package:package |
|
324 "a packages directory as filename" |
|
325 |
|
326 self halt. |
|
327 "/ |dir| |
|
328 "/ |
|
329 "/ dir := self moduleDirectoryFor:moduleDir. |
|
330 "/ ^ dir construct:package |
|
331 |
|
332 "Created: / 21-12-2011 / 18:43:27 / cg" |
|
333 ! |
|
334 |
|
335 revisionInfoFromString:aString |
|
336 "{ Pragma: +optSpace }" |
|
337 |
|
338 "return a VersionInfo object filled with revision info. |
|
339 This extracts the relevant info from aString." |
|
340 |
|
341 |info path version user ts timeStamp idx1 idx2| |
|
342 |
|
343 "/ 'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826' |
|
344 |
|
345 idx1 := aString indexOfSubCollection:'Path: '. |
|
346 idx1 ~~ 0 ifTrue:[ |
|
347 idx1 := idx1 + 'Path: ' size. |
|
348 idx2 := aString indexOfSubCollection:', ' startingAt:idx1. |
|
349 path := aString copyFrom:idx1 to:idx2-1. |
|
350 ]. |
|
351 idx1 := aString indexOfSubCollection:'Version: '. |
|
352 idx1 ~~ 0 ifTrue:[ |
|
353 idx1 := idx1 + 'Version: ' size. |
|
354 idx2 := aString indexOfSubCollection:', ' startingAt:idx1. |
|
355 idx2 == 0 ifTrue:[ |
|
356 version := aString copyFrom:idx1 |
|
357 ] ifFalse:[ |
|
358 version := aString copyFrom:idx1 to:idx2-1. |
|
359 ]. |
|
360 ]. |
|
361 idx1 := aString indexOfSubCollection:'User: '. |
|
362 idx1 ~~ 0 ifTrue:[ |
|
363 idx1 := idx1 + 'User: ' size. |
|
364 idx2 := aString indexOfSubCollection:', ' startingAt:idx1. |
|
365 idx2 == 0 ifTrue:[ |
|
366 user := aString copyFrom:idx1 |
|
367 ] ifFalse:[ |
|
368 user := aString copyFrom:idx1 to:idx2-1. |
|
369 ]. |
|
370 ]. |
|
371 idx1 := aString indexOfSubCollection:'Time: '. |
|
372 idx1 ~~ 0 ifTrue:[ |
|
373 idx1 := idx1 + 'Time: ' size. |
|
374 idx2 := aString indexOfSubCollection:', ' startingAt:idx1. |
|
375 idx2 == 0 ifTrue:[ |
|
376 ts := aString copyFrom:idx1 |
|
377 ] ifFalse:[ |
|
378 ts := aString copyFrom:idx1 to:idx2-1. |
|
379 ]. |
|
380 timeStamp := Timestamp readIso8601FormatFrom:ts |
|
381 ]. |
|
382 |
|
383 info := VersionInfo new. |
|
384 path notNil ifTrue:[ info fileName:(path asFilename baseName) ]. |
|
385 info revision:version. |
|
386 user notNil ifTrue:[ info user:user ]. |
|
387 timeStamp notNil ifTrue:[ info timeStamp:timeStamp ]. |
|
388 ^ info |
|
389 |
|
390 " |
|
391 self revisionInfoFromString:'Path: stx/libbasic/Array.st, Version: 123, User: cg, Time: 2011-12-21T21:03:08.826' |
|
392 " |
|
393 |
|
394 "Created: / 21-12-2011 / 14:50:12 / cg" |
|
395 ! |
|
396 |
|
397 revisionLogOf:clsOrNil fromRevision:rev1OrNil toRevision:rev2OrNil numberOfRevisions:limitOrNil fileName:classFileName directory:packageDir module:moduleDir |
|
398 "Return true if ok, false if not." |
|
399 |
|
400 self halt. |
|
401 "/ |info log targetDir count newestRevision| |
|
402 "/ |
|
403 "/ targetDir := self packageDirectoryForModule:moduleDir package:packageDir. |
|
404 "/ targetDir exists ifFalse:[^ nil ]. |
|
405 "/ |
|
406 "/ info := IdentityDictionary new. |
|
407 "/ log := OrderedCollection new. |
|
408 "/ count := 0. |
|
409 "/ |
|
410 "/ (targetDir filesMatching:(classFileName,'_*')) do:[:eachVersionFile | |
|
411 "/ |versionString cs versionChange info| |
|
412 "/ |
|
413 "/ versionString := eachVersionFile copyFrom:(classFileName size + 2). |
|
414 "/ count := count + 1. |
|
415 "/ (newestRevision isNil |
|
416 "/ or:[ self isRevision:versionString after:newestRevision ]) ifTrue:[ |
|
417 "/ newestRevision := versionString |
|
418 "/ ]. |
|
419 "/ |
|
420 "/ (rev1OrNil isNil |
|
421 "/ or:[ rev1OrNil = 0 |
|
422 "/ or:[ versionString = rev1OrNil |
|
423 "/ or:[ self isRevision:versionString after:rev1OrNil ]]]) |
|
424 "/ ifTrue:[ |
|
425 "/ (rev2OrNil isNil |
|
426 "/ or:[ rev2OrNil = 0 |
|
427 "/ or:[ versionString = rev2OrNil |
|
428 "/ or:[ self isRevision:rev2OrNil after:versionString ]]]) |
|
429 "/ ifTrue:[ |
|
430 "/ (limitOrNil isNil |
|
431 "/ or:[ log size < limitOrNil ]) |
|
432 "/ ifTrue:[ |
|
433 "/ cs := ChangeSet fromFile:(targetDir construct:eachVersionFile). |
|
434 "/ versionChange := cs detect:[:chg | chg isMethodChange |
|
435 "/ and:[chg selector = self nameOfVersionMethodInClasses]] |
|
436 "/ ifNone:nil. |
|
437 "/ versionChange notNil ifTrue:[ |
|
438 "/ info := self revisionInfoFromString:versionChange source. |
|
439 "/ ] ifFalse:[ |
|
440 "/ info := VersionInfo new. |
|
441 "/ ]. |
|
442 "/ |
|
443 "/ info revision:versionString. |
|
444 "/ log add:info. |
|
445 "/ ] |
|
446 "/ ]. |
|
447 "/ ]. |
|
448 "/ ]. |
|
449 "/ log sort:[:a :b | self isRevision:b revision after:a revision]. |
|
450 "/ |
|
451 "/ info at:#revisions put:log. |
|
452 "/ info at:#numberOfRevisions put:count. |
|
453 "/ info at:#newestRevision put:newestRevision. |
|
454 "/ |
|
455 "/ ^ info |
|
456 "/ |
|
457 "/ |
|
458 |
|
459 "Created: / 21-12-2011 / 20:39:31 / cg" |
|
460 ! |
|
461 |
|
462 revisionStringFor:aClass inModule:moduleDir directory:packageDir container:fileName revision:revisionString |
|
463 "return a string usable as initial revision string" |
|
464 |
|
465 ^ 'Path: %1/%2/%3, Version: %4, User: %5, Time: %6' |
|
466 bindWith:moduleDir |
|
467 with:packageDir |
|
468 with:fileName |
|
469 with:revisionString |
|
470 with:(OperatingSystem getLoginName) |
|
471 with:(Timestamp now printStringIso8601Format) |
|
472 |
|
473 " |
|
474 self revisionStringFor:Array inModule:'stx' directory:'libbasic' container:'Array.st' revision:'123' |
|
475 " |
|
476 |
|
477 "Created: / 21-12-2011 / 19:33:33 / cg" |
|
478 ! |
|
479 |
|
480 streamForClass:aClass fileName:classFileName revision:revision directory:packageDir module:moduleDir cache:doCache |
|
481 self halt. |
|
482 "/ |targetDir oldFile| |
|
483 "/ |
|
484 "/ targetDir := self packageDirectoryForModule:moduleDir package:packageDir. |
|
485 "/ oldFile := (targetDir construct:classFileName,'_',revision). |
|
486 "/ ^ oldFile readStream |
|
487 |
|
488 "Created: / 21-12-2011 / 20:49:01 / cg" |
|
489 ! ! |
|
490 |
|
491 !DataBaseSourceCodeManager class methodsFor:'documentation'! |
|
492 |
|
493 version |
|
494 ^ '$Header: /cvs/stx/stx/libbasic3/DataBaseSourceCodeManager.st,v 1.1 2011-12-22 13:03:16 cg Exp $' |
|
495 ! |
|
496 |
|
497 version_CVS |
|
498 ^ '$Header: /cvs/stx/stx/libbasic3/DataBaseSourceCodeManager.st,v 1.1 2011-12-22 13:03:16 cg Exp $' |
|
499 ! ! |