# HG changeset patch
# User Jan Vrany <jan.vrany@labware.com>
# Date 1613723381 0
# Fri Feb 19 08:29:41 2021 +0000
# Node ID 935264ad298af5260a0e566cdbad4a5cb341ccbe
# Parent ed037226b5684fc4017d4948a5700a3931bb0dc3
Rework and fix HGSourceCodeManager >> #revisionLogOf:...directory:module:`
This commit changes the logic in two ways:
1. #newestRevision is now the newest revision in the branch that
*contains* given file (not necesarily modidfes it). If there are
multiple heads in that branch, pretty much random one is returned.
This changes old behavior and therefore this commit updates
tests.
2. If a specific single revision is requested, i.e., both from and to revisions
are the same, revision log with that single revision is returned
no matter whether it modifies the file or even contains that file
at all. This is essentially a workaround to fix issue #305.
Moreover, this commit simplifies the code a lot by delegating all the
changeset searching and filtering to mercurial using revset expressions.
See https://swing.fit.cvut.cz/projects/stx-jv/ticket/305#comment:3
diff -r ed037226b568 -r 935264ad298a mercurial/HGSourceCodeManager.st
a
|
b
|
|
1 | 1 | " |
2 | 2 | stx:libscm - a new source code management library for Smalltalk/X |
3 | 3 | Copyright (C) 2012-2015 Jan Vrany |
4 | | Copyright (C) 2020 LabWare |
| 4 | Copyright (C) 2020-2021 LabWare |
5 | 5 | |
6 | 6 | This library is free software; you can redistribute it and/or |
7 | 7 | modify it under the terms of the GNU Lesser General Public |
… |
… |
|
34 | 34 | " |
35 | 35 | stx:libscm - a new source code management library for Smalltalk/X |
36 | 36 | Copyright (C) 2012-2015 Jan Vrany |
37 | | Copyright (C) 2020 LabWare |
| 37 | Copyright (C) 2020-2021 LabWare |
38 | 38 | |
39 | 39 | This library is free software; you can redistribute it and/or |
40 | 40 | modify it under the terms of the GNU Lesser General Public |
… |
… |
|
297 | 297 | "Actually do return a revisionLog. The main worker method. This must be implemented by a |
298 | 298 | concrete source-code manager. The interface of this method is just crazy!! |
299 | 299 | |
300 | | If numRevisionsOrNil is notNil, it limits the number of revision records returned - |
301 | | only numRevions of the newest revision infos will be collected. |
| 300 | If `limitOrNil` is notNil, it limits the number of revision records returned - |
| 301 | only `limitOrNil` of the newest revision infos will be collected. |
302 | 302 | |
303 | 303 | The returned information is a structure (IdentityDictionary) |
304 | 304 | filled with: |
… |
… |
|
330 | 330 | revisions are ordered newest first |
331 | 331 | (i.e. the last entry is for the initial revision; the first for the most recent one) |
332 | 332 | Attention: if state = 'dead' that revision is no longer valid. |
| 333 | |
| 334 | WARNING: The interface, apart from being crazy, is also designed upon assumption |
| 335 | that file has been changed in all revisions. This is essentially true only for |
| 336 | CVS (per-file versioning) and does not hold for any modern SCM. Also, it does to take |
| 337 | branches into an account. And so on. |
| 338 | |
| 339 | Therefore here we do some really nasty hacks to make sure we answer what's expected |
| 340 | by various and many callers and hope it will appear to work. There's little else to |
| 341 | do here, the problem is the *broken-by-design* interface of source code manager API. |
333 | 342 | " |
334 | 343 | |
335 | | | pkg repo path wcentry info newest oldest startRev stopRev limit log revs startRevIndex stopRevIndex revIndex | |
| 344 | | pkg repo path wcentry info newestRev log revs | |
336 | 345 | |
337 | 346 | info := IdentityDictionary new. |
338 | 347 | pkg := HGPackageWorkingCopy named: (moduleDir , ':' , packageDir). |
… |
… |
|
343 | 352 | self breakPoint: #jv info: 'Ooops, could not found given file in working copy. Changeset scanning not yet implemented. You may proceed wot'. |
344 | 353 | ^ nil |
345 | 354 | ]. |
346 | | revs := (rev1OrNil == 0 and:[rev2OrNil == 0]) |
347 | | ifTrue:[((wcentry changeset / path / classFileName) newer: true) collect:[:f|f changeset]] |
348 | | ifFalse:[wcentry revisions collect:[:f|f changeset]]. |
349 | | revs isEmpty ifTrue:[revs add: wcentry changeset]. |
350 | | newest := revs first. |
351 | | oldest := revs last. |
| 355 | |
| 356 | "/ Here, the newest revision for 'header' is always the newest revision |
| 357 | "/ in the same branch that contains (not neccesarrily modifies!!) the class. |
| 358 | "/ Does not care about multiple heads within branch, just return "some", but |
| 359 | "/ there's not much else to do due to the method interface. |
| 360 | "/ |
| 361 | "/ Hope that's okay with callers. |
| 362 | revs := repo changesetsMatching: ('last(contains("%1") and branch("%2"),1)' |
| 363 | bindWith: wcentry pathNameRelative |
| 364 | with: repo workingCopy branch name). |
| 365 | self assert: revs size == 1. |
| 366 | newestRev := revs first. |
352 | 367 | |
353 | 368 | info at:#container put: classFileName. "/ -> the revision string |
354 | 369 | info at:#cvsRoot put: repo pathName. "/ -> the CVS root (repository) |
355 | 370 | info at:#filename put: classFileName. "/ -> the actual source file name |
356 | | info at:#newestRevision put: newest id printString. "/-> the revisionString of the newest revision |
357 | | info at:#numberOfRevisions put: newest id revno. |
| 371 | info at:#newestRevision put: newestRev id printString. "/ -> the revisionString of the newest revision |
| 372 | info at:#numberOfRevisions put: newestRev id revno. |
| 373 | |
| 374 | "/ (rev1OrNil == 0 and:[rev2OrNil == 0]) ifTrue:[ |
| 375 | "/ ^ info |
| 376 | "/ ]. |
| 377 | |
| 378 | (rev1OrNil notNil and:[ rev1OrNil = rev2OrNil ]) ifTrue: [ |
| 379 | "/ If we're asked for specific revision, return just that one |
| 380 | "/ *NO MATTER* whether it modifies the class or not. |
| 381 | revs := Array with: repo @ rev1OrNil. |
| 382 | ] ifFalse: [ |
| 383 | "/ If we're asked for revision range, only return those in that |
| 384 | "/ range that *ACTUALLY MODIFIES* the file. |
358 | 385 | |
359 | | (rev1OrNil == 0 and:[rev2OrNil == 0]) ifTrue:[ |
360 | | limit := 1. |
361 | | startRev := newest. |
362 | | stopRev := newest. |
363 | | ] ifFalse:[ |
364 | | limit := limitOrNil ? (revs size) . |
365 | | startRev := rev1OrNil isNil ifTrue:[newest] ifFalse:[repo @ rev1OrNil]. |
366 | | stopRev := rev2OrNil isNil ifTrue:[oldest] ifFalse:[repo @ rev2OrNil]. |
| 386 | | from to revset | |
| 387 | |
| 388 | from := rev2OrNil isNil ifTrue:['0'] ifFalse:[rev2OrNil]. |
| 389 | to := rev1OrNil isNil ifTrue:['tip'] ifFalse:[rev1OrNil]. |
| 390 | |
| 391 | revset := '%1:%2 and file("%3") and branch("%4")' |
| 392 | bindWith: from |
| 393 | with: to |
| 394 | with: wcentry pathNameRelative |
| 395 | with: repo workingCopy branch name. |
| 396 | limitOrNil notNil ifTrue: [ |
| 397 | revset := 'last(%1, %2)' bindWith: revset with: limitOrNil |
| 398 | ]. |
| 399 | |
| 400 | revs := repo changesetsMatching: revset. |
367 | 401 | ]. |
| 402 | |
368 | 403 | log := OrderedCollection new. |
369 | 404 | |
370 | | startRevIndex := revs indexOf: startRev. |
371 | | stopRevIndex := revs indexOf: stopRev. |
372 | | limit := limit min: (stopRevIndex - startRevIndex + 1). |
| 405 | revs reverseDo: [:rev | |
| 406 | | entry | |
373 | 407 | |
374 | | revIndex := startRevIndex. |
375 | | limit timesRepeat:[ |
376 | | | entry rev | |
377 | | rev := revs at: revIndex. |
378 | | entry := IdentityDictionary new. |
| 408 | entry := IdentityDictionary new. |
379 | 409 | entry at:#revision put: rev id printString."/ -> the revision string |
380 | 410 | entry at:#author put: rev author."/ -> who checked that revision into the repository |
381 | 411 | entry at:#date put: rev timestamp printString."/ -> when was it checked in |
… |
… |
|
383 | 413 | entry at:#numberOfChangedLines put: 'N/A'. "/ -> the number of changed line w.r.t the previous |
384 | 414 | entry at:#logMessage put: rev message."/ -> the checkIn log message. |
385 | 415 | log add: entry. |
386 | | |
387 | | revIndex := revIndex + 1. |
388 | 416 | ]. |
389 | 417 | info at: #revisions put: log. |
390 | 418 | |
391 | 419 | ^info |
392 | 420 | |
393 | 421 | "Modified: / 24-04-2016 / 13:19:44 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 422 | "Modified: / 19-02-2021 / 07:54:22 / Jan Vrany <jan.vrany@labware.com>" |
394 | 423 | ! ! |
395 | 424 | |
396 | 425 | !HGSourceCodeManager class methodsFor:'queries'! |
diff -r ed037226b568 -r 935264ad298a mercurial/HGStXTests.st
a
|
b
|
|
4265 | 4265 | |
4266 | 4266 | !HGStXTests methodsFor:'tests - manager API'! |
4267 | 4267 | |
| 4268 | test_issue_305a |
| 4269 | | rev log | |
| 4270 | |
| 4271 | rev := HGSourceCodeManager newestRevisionOf: HGTestCase. |
| 4272 | log := HGSourceCodeManager revisionLogOf:HGTestCase fromRevision:rev toRevision: rev. |
| 4273 | |
| 4274 | "Created: / 18-02-2021 / 20:45:30 / Jan Vrany <jan.vrany@labware.com>" |
| 4275 | ! |
| 4276 | |
4268 | 4277 | test_log_01 |
4269 | 4278 | |
4270 | 4279 | | log repo | |
… |
… |
|
4462 | 4471 | |
4463 | 4472 | self assert: (log at: #container) = 'MocksHGP6Bar.st'. |
4464 | 4473 | self assert: (log at: #cvsRoot) = repo pathName. |
4465 | | self assert: (log at: #newestRevision) = '4:f71dfc6c6f9b'. |
| 4474 | self assert: (log at: #newestRevision) = '6:7d0045fb7dba'. |
4466 | 4475 | self assert: (log at: #revisions) size == 1. |
4467 | 4476 | self assert: ((log at: #revisions) first at:#revision) = '0:c76faa501252'. |
4468 | 4477 | |
4469 | 4478 | "Created: / 11-02-2014 / 11:31:27 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
4470 | 4479 | "Modified: / 11-02-2014 / 12:58:04 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 4480 | "Modified: / 19-02-2021 / 07:55:27 / Jan Vrany <jan.vrany@labware.com>" |
4471 | 4481 | ! |
4472 | 4482 | |
4473 | 4483 | test_log_05b |
… |
… |
|
4491 | 4501 | |
4492 | 4502 | self assert: (log at: #container) = 'MocksHGP6Foo.st'. |
4493 | 4503 | self assert: (log at: #cvsRoot) = repo pathName. |
4494 | | self assert: (log at: #newestRevision) = '0:c76faa501252'. |
| 4504 | self assert: (log at: #newestRevision) = '6:7d0045fb7dba'. |
4495 | 4505 | self assert: (log at: #revisions) size == 1. |
4496 | 4506 | self assert: ((log at: #revisions) first at:#revision) = '0:c76faa501252'. |
4497 | 4507 | |
4498 | 4508 | "Created: / 11-02-2014 / 11:34:32 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
4499 | 4509 | "Modified: / 11-02-2014 / 13:55:09 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 4510 | "Modified: / 19-02-2021 / 07:55:45 / Jan Vrany <jan.vrany@labware.com>" |
4500 | 4511 | ! |
4501 | 4512 | |
4502 | 4513 | test_newestRevisionOf_01 |
… |
… |
|
4507 | 4518 | |
4508 | 4519 | rev := HGSourceCodeManager newestRevisionOf: (Smalltalk at: #MocksHGP6Bar). |
4509 | 4520 | |
4510 | | self assert: rev = '4:f71dfc6c6f9b'. |
| 4521 | self assert: rev = '6:7d0045fb7dba'. |
4511 | 4522 | |
4512 | 4523 | "Created: / 24-04-2016 / 11:41:44 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 4524 | "Modified: / 19-02-2021 / 07:11:46 / Jan Vrany <jan.vrany@labware.com>" |
4513 | 4525 | ! |
4514 | 4526 | |
4515 | 4527 | test_newestRevisionOf_02 |
… |
… |
|
4520 | 4532 | |
4521 | 4533 | rev := HGSourceCodeManager newestRevisionOf: (Smalltalk at: #MocksHGP6Bar). |
4522 | 4534 | |
4523 | | self assert: rev = '4:f71dfc6c6f9b'. |
| 4535 | self assert: rev = '6:7d0045fb7dba'. |
4524 | 4536 | |
4525 | 4537 | "Created: / 24-04-2016 / 11:46:17 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 4538 | "Modified: / 19-02-2021 / 07:14:03 / Jan Vrany <jan.vrany@labware.com>" |
4526 | 4539 | ! |
4527 | 4540 | |
4528 | 4541 | test_newestRevisionOf_03a |
… |
… |
|
4533 | 4546 | |
4534 | 4547 | rev := HGSourceCodeManager newestRevisionOf: (Smalltalk at: #MocksHGP6Foo). |
4535 | 4548 | |
4536 | | self assert: rev = '2:581b3cabbf8f'. |
| 4549 | self assert: rev = '6:7d0045fb7dba'. |
4537 | 4550 | |
4538 | 4551 | "Created: / 24-04-2016 / 11:47:50 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 4552 | "Modified: / 19-02-2021 / 07:12:32 / Jan Vrany <jan.vrany@labware.com>" |
4539 | 4553 | ! |
4540 | 4554 | |
4541 | 4555 | test_newestRevisionOf_03b |
… |
… |
|
4551 | 4565 | package: 'mocks:hg/p6'. |
4552 | 4566 | rev := HGSourceCodeManager newestRevisionOf: (Smalltalk at: #MocksHGP6Foo). |
4553 | 4567 | |
4554 | | self assert: rev = '4:f71dfc6c6f9b'. |
| 4568 | self assert: rev = '6:7d0045fb7dba'. |
4555 | 4569 | |
4556 | 4570 | "Created: / 24-04-2016 / 11:48:28 / Jan Vrany <jan.vrany@fit.cvut.cz>" |
| 4571 | "Modified: / 19-02-2021 / 07:13:11 / Jan Vrany <jan.vrany@labware.com>" |
4557 | 4572 | ! |
4558 | 4573 | |
4559 | 4574 | test_newestRevisionOf_03c |