Mercurial > hg > sonic-visualiser
comparison vext.sml @ 1740:669bd699082d
Update vext
author | Chris Cannam |
---|---|
date | Thu, 13 Jul 2017 15:34:33 +0100 |
parents | 76872ffc03a3 |
children | bf4a7015033e |
comparison
equal
deleted
inserted
replaced
1739:713ab804d16e | 1740:669bd699082d |
---|---|
31 Particular Programs Ltd shall not be used in advertising or | 31 Particular Programs Ltd shall not be used in advertising or |
32 otherwise to promote the sale, use or other dealings in this | 32 otherwise to promote the sale, use or other dealings in this |
33 Software without prior written authorization. | 33 Software without prior written authorization. |
34 *) | 34 *) |
35 | 35 |
36 val vext_version = "0.9.4" | 36 val vext_version = "0.9.6" |
37 | 37 |
38 | 38 |
39 datatype vcs = | 39 datatype vcs = |
40 HG | | 40 HG | |
41 GIT | 41 GIT |
46 service : string, | 46 service : string, |
47 owner : string option, | 47 owner : string option, |
48 repo : string option | 48 repo : string option |
49 } | 49 } |
50 | 50 |
51 type id_or_tag = string | |
52 | |
51 datatype pin = | 53 datatype pin = |
52 UNPINNED | | 54 UNPINNED | |
53 PINNED of string | 55 PINNED of id_or_tag |
54 | 56 |
55 datatype libstate = | 57 datatype libstate = |
56 ABSENT | | 58 ABSENT | |
57 CORRECT | | 59 CORRECT | |
58 SUPERSEDED | | 60 SUPERSEDED | |
59 WRONG | 61 WRONG |
60 | 62 |
61 datatype localstate = | 63 datatype localstate = |
62 MODIFIED | | 64 MODIFIED | |
63 UNMODIFIED | 65 LOCK_MISMATCHED | |
66 CLEAN | |
64 | 67 |
65 datatype branch = | 68 datatype branch = |
66 BRANCH of string | | 69 BRANCH of string | |
67 DEFAULT_BRANCH | 70 DEFAULT_BRANCH |
68 | 71 |
75 OK of 'a | | 78 OK of 'a | |
76 ERROR of string | 79 ERROR of string |
77 | 80 |
78 type libname = string | 81 type libname = string |
79 | 82 |
80 type id_or_tag = string | |
81 | |
82 type libspec = { | 83 type libspec = { |
83 libname : libname, | 84 libname : libname, |
84 vcs : vcs, | 85 vcs : vcs, |
85 source : source, | 86 source : source, |
86 branch : branch, | 87 branch : branch, |
87 pin : pin | 88 project_pin : pin, |
89 lock_pin : pin | |
88 } | 90 } |
89 | 91 |
90 type lock = { | 92 type lock = { |
91 libname : libname, | 93 libname : libname, |
92 id_or_tag : id_or_tag | 94 id_or_tag : id_or_tag |
93 } | 95 } |
94 | 96 |
95 type remote_spec = { | 97 type remote_spec = { |
96 anon : string option, | 98 anon : string option, |
97 auth : string option | 99 auth : string option |
98 } | 100 } |
99 | 101 |
175 | 177 |
176 signature LIB_CONTROL = sig | 178 signature LIB_CONTROL = sig |
177 val review : context -> libspec -> (libstate * localstate) result | 179 val review : context -> libspec -> (libstate * localstate) result |
178 val status : context -> libspec -> (libstate * localstate) result | 180 val status : context -> libspec -> (libstate * localstate) result |
179 val update : context -> libspec -> id_or_tag result | 181 val update : context -> libspec -> id_or_tag result |
182 val id_of : context -> libspec -> id_or_tag result | |
180 end | 183 end |
181 | 184 |
182 structure FileBits :> sig | 185 structure FileBits :> sig |
183 val extpath : context -> string | 186 val extpath : context -> string |
184 val libpath : context -> libname -> string | 187 val libpath : context -> libname -> string |
400 - WRONG: We are at any revision other than the pinned one. | 403 - WRONG: We are at any revision other than the pinned one. |
401 | 404 |
402 - ABSENT: Repo doesn't exist here at all. | 405 - ABSENT: Repo doesn't exist here at all. |
403 *) | 406 *) |
404 | 407 |
405 fun check with_network context ({ libname, branch, pin, ... } : libspec) = | 408 fun check with_network context |
409 ({ libname, branch, project_pin, lock_pin, ... } : libspec) = | |
406 let fun check_unpinned () = | 410 let fun check_unpinned () = |
407 let val is_newest = if with_network | 411 let val is_newest = if with_network |
408 then V.is_newest | 412 then V.is_newest |
409 else V.is_newest_locally | 413 else V.is_newest_locally |
410 in | 414 in |
420 fun check_pinned target = | 424 fun check_pinned target = |
421 case V.is_at context (libname, target) of | 425 case V.is_at context (libname, target) of |
422 ERROR e => ERROR e | 426 ERROR e => ERROR e |
423 | OK true => OK CORRECT | 427 | OK true => OK CORRECT |
424 | OK false => OK WRONG | 428 | OK false => OK WRONG |
425 fun check' () = | 429 fun check_remote () = |
426 case pin of | 430 case project_pin of |
427 UNPINNED => check_unpinned () | 431 UNPINNED => check_unpinned () |
428 | PINNED target => check_pinned target | 432 | PINNED target => check_pinned target |
433 fun check_local () = | |
434 case V.is_modified_locally context libname of | |
435 ERROR e => ERROR e | |
436 | OK true => OK MODIFIED | |
437 | OK false => | |
438 case lock_pin of | |
439 UNPINNED => OK CLEAN | |
440 | PINNED target => | |
441 case V.is_at context (libname, target) of | |
442 ERROR e => ERROR e | |
443 | OK true => OK CLEAN | |
444 | OK false => OK LOCK_MISMATCHED | |
429 in | 445 in |
430 case V.exists context libname of | 446 case V.exists context libname of |
431 ERROR e => ERROR e | 447 ERROR e => ERROR e |
432 | OK false => OK (ABSENT, UNMODIFIED) | 448 | OK false => OK (ABSENT, CLEAN) |
433 | OK true => | 449 | OK true => |
434 case (check' (), V.is_modified_locally context libname) of | 450 case (check_remote (), check_local ()) of |
435 (ERROR e, _) => ERROR e | 451 (ERROR e, _) => ERROR e |
436 | (_, ERROR e) => ERROR e | 452 | (_, ERROR e) => ERROR e |
437 | (OK state, OK true) => OK (state, MODIFIED) | 453 | (OK r, OK l) => OK (r, l) |
438 | (OK state, OK false) => OK (state, UNMODIFIED) | |
439 end | 454 end |
440 | 455 |
441 val review = check true | 456 val review = check true |
442 val status = check false | 457 val status = check false |
443 | 458 |
444 fun update context ({ libname, source, branch, pin, ... } : libspec) = | 459 fun update context |
460 ({ libname, source, branch, | |
461 project_pin, lock_pin, ... } : libspec) = | |
445 let fun update_unpinned () = | 462 let fun update_unpinned () = |
446 case V.is_newest context (libname, branch) of | 463 case V.is_newest context (libname, branch) of |
447 ERROR e => ERROR e | 464 ERROR e => ERROR e |
448 | OK true => V.id_of context libname | 465 | OK true => V.id_of context libname |
449 | OK false => V.update context (libname, branch) | 466 | OK false => V.update context (libname, branch) |
451 case V.is_at context (libname, target) of | 468 case V.is_at context (libname, target) of |
452 ERROR e => ERROR e | 469 ERROR e => ERROR e |
453 | OK true => OK target | 470 | OK true => OK target |
454 | OK false => V.update_to context (libname, target) | 471 | OK false => V.update_to context (libname, target) |
455 fun update' () = | 472 fun update' () = |
456 case pin of | 473 case lock_pin of |
457 UNPINNED => update_unpinned () | 474 PINNED target => update_pinned target |
458 | PINNED target => update_pinned target | 475 | UNPINNED => |
476 case project_pin of | |
477 PINNED target => update_pinned target | |
478 | UNPINNED => update_unpinned () | |
459 in | 479 in |
460 case V.exists context libname of | 480 case V.exists context libname of |
461 ERROR e => ERROR e | 481 ERROR e => ERROR e |
462 | OK true => update' () | 482 | OK true => update' () |
463 | OK false => | 483 | OK false => |
464 case V.checkout context (libname, source, branch) of | 484 case V.checkout context (libname, source, branch) of |
465 ERROR e => ERROR e | 485 ERROR e => ERROR e |
466 | OK () => update' () | 486 | OK () => update' () |
467 end | 487 end |
488 | |
489 fun id_of context ({ libname, ... } : libspec) = | |
490 V.id_of context libname | |
491 | |
468 end | 492 end |
469 | 493 |
470 (* Simple Standard ML JSON parser | 494 (* Simple Standard ML JSON parser |
471 ============================== | 495 ============================== |
472 | 496 |
1367 fun status context (spec as { vcs, ... } : libspec) = | 1391 fun status context (spec as { vcs, ... } : libspec) = |
1368 (fn HG => H.status | GIT => G.status) vcs context spec | 1392 (fn HG => H.status | GIT => G.status) vcs context spec |
1369 | 1393 |
1370 fun update context (spec as { vcs, ... } : libspec) = | 1394 fun update context (spec as { vcs, ... } : libspec) = |
1371 (fn HG => H.update | GIT => G.update) vcs context spec | 1395 (fn HG => H.update | GIT => G.update) vcs context spec |
1396 | |
1397 fun id_of context (spec as { vcs, ... } : libspec) = | |
1398 (fn HG => H.id_of | GIT => G.id_of) vcs context spec | |
1372 end | 1399 end |
1373 | 1400 |
1374 val libobjname = "libraries" | 1401 val libobjname = "libraries" |
1375 | 1402 |
1376 fun load_libspec spec_json lock_json libname : libspec = | 1403 fun load_libspec spec_json lock_json libname : libspec = |
1381 val service = retrieve ["service"] | 1408 val service = retrieve ["service"] |
1382 val owner = retrieve ["owner"] | 1409 val owner = retrieve ["owner"] |
1383 val repo = retrieve ["repository"] | 1410 val repo = retrieve ["repository"] |
1384 val url = retrieve ["url"] | 1411 val url = retrieve ["url"] |
1385 val branch = retrieve ["branch"] | 1412 val branch = retrieve ["branch"] |
1386 val user_pin = retrieve ["pin"] | 1413 val project_pin = case retrieve ["pin"] of |
1414 NONE => UNPINNED | |
1415 | SOME p => PINNED p | |
1387 val lock_pin = case lookup_optional lock_json [libobjname, libname] of | 1416 val lock_pin = case lookup_optional lock_json [libobjname, libname] of |
1388 SOME ll => lookup_optional_string ll ["pin"] | 1417 NONE => UNPINNED |
1389 | NONE => NONE | 1418 | SOME ll => case lookup_optional_string ll ["pin"] of |
1419 SOME p => PINNED p | |
1420 | NONE => UNPINNED | |
1390 in | 1421 in |
1391 { | 1422 { |
1392 libname = libname, | 1423 libname = libname, |
1393 vcs = case vcs of | 1424 vcs = case vcs of |
1394 "hg" => HG | 1425 "hg" => HG |
1399 (SOME u, NONE, _, _) => URL_SOURCE u | 1430 (SOME u, NONE, _, _) => URL_SOURCE u |
1400 | (NONE, SOME ss, owner, repo) => | 1431 | (NONE, SOME ss, owner, repo) => |
1401 SERVICE_SOURCE { service = ss, owner = owner, repo = repo } | 1432 SERVICE_SOURCE { service = ss, owner = owner, repo = repo } |
1402 | _ => raise Fail ("Must have exactly one of service " ^ | 1433 | _ => raise Fail ("Must have exactly one of service " ^ |
1403 "or url string"), | 1434 "or url string"), |
1404 pin = case lock_pin of | 1435 project_pin = project_pin, |
1405 SOME p => PINNED p | 1436 lock_pin = lock_pin, |
1406 | NONE => | |
1407 case user_pin of | |
1408 SOME p => PINNED p | |
1409 | NONE => UNPINNED, | |
1410 branch = case branch of | 1437 branch = case branch of |
1411 SOME b => BRANCH b | 1438 SOME b => BRANCH b |
1412 | NONE => DEFAULT_BRANCH | 1439 | NONE => DEFAULT_BRANCH |
1413 } | 1440 } |
1414 end | 1441 end |
1500 fun hline_to 0 = "" | 1527 fun hline_to 0 = "" |
1501 | hline_to n = "-" ^ hline_to (n-1) | 1528 | hline_to n = "-" ^ hline_to (n-1) |
1502 | 1529 |
1503 val libname_width = 25 | 1530 val libname_width = 25 |
1504 val libstate_width = 11 | 1531 val libstate_width = 11 |
1505 val localstate_width = 9 | 1532 val localstate_width = 17 |
1506 val notes_width = 5 | 1533 val notes_width = 5 |
1507 val divider = " | " | 1534 val divider = " | " |
1535 val clear_line = "\r" ^ pad_to 80 ""; | |
1508 | 1536 |
1509 fun print_status_header () = | 1537 fun print_status_header () = |
1510 print ("\r" ^ pad_to 80 "" ^ "\n " ^ | 1538 print (clear_line ^ "\n " ^ |
1511 pad_to libname_width "Library" ^ divider ^ | 1539 pad_to libname_width "Library" ^ divider ^ |
1512 pad_to libstate_width "State" ^ divider ^ | 1540 pad_to libstate_width "State" ^ divider ^ |
1513 pad_to localstate_width "Local" ^ divider ^ | 1541 pad_to localstate_width "Local" ^ divider ^ |
1514 "Notes" ^ "\n " ^ | 1542 "Notes" ^ "\n " ^ |
1515 hline_to libname_width ^ "-+-" ^ | 1543 hline_to libname_width ^ "-+-" ^ |
1516 hline_to libstate_width ^ "-+-" ^ | 1544 hline_to libstate_width ^ "-+-" ^ |
1517 hline_to localstate_width ^ "-+-" ^ | 1545 hline_to localstate_width ^ "-+-" ^ |
1518 hline_to notes_width ^ "\n") | 1546 hline_to notes_width ^ "\n") |
1519 | 1547 |
1520 fun print_outcome_header () = | 1548 fun print_outcome_header () = |
1521 print ("\r" ^ pad_to 80 "" ^ "\n " ^ | 1549 print (clear_line ^ "\n " ^ |
1522 pad_to libname_width "Library" ^ divider ^ | 1550 pad_to libname_width "Library" ^ divider ^ |
1523 pad_to libstate_width "Outcome" ^ divider ^ | 1551 pad_to libstate_width "Outcome" ^ divider ^ |
1524 "Notes" ^ "\n " ^ | 1552 "Notes" ^ "\n " ^ |
1525 hline_to libname_width ^ "-+-" ^ | 1553 hline_to libname_width ^ "-+-" ^ |
1526 hline_to libstate_width ^ "-+-" ^ | 1554 hline_to libstate_width ^ "-+-" ^ |
1535 | OK (WRONG, _) => "Wrong" | 1563 | OK (WRONG, _) => "Wrong" |
1536 | ERROR _ => "Error" | 1564 | ERROR _ => "Error" |
1537 val localstate_str = | 1565 val localstate_str = |
1538 case status of | 1566 case status of |
1539 OK (_, MODIFIED) => "Modified" | 1567 OK (_, MODIFIED) => "Modified" |
1540 | OK (_, UNMODIFIED) => "Clean" | 1568 | OK (_, LOCK_MISMATCHED) => "Differs from Lock" |
1541 | _ => "" | 1569 | OK (_, CLEAN) => "Clean" |
1570 | ERROR _ => "" | |
1542 val error_str = | 1571 val error_str = |
1543 case status of | 1572 case status of |
1544 ERROR e => e | 1573 ERROR e => e |
1545 | _ => "" | 1574 | _ => "" |
1546 in | 1575 in |
1610 then save_lock_file (#rootpath context) locks | 1639 then save_lock_file (#rootpath context) locks |
1611 else (); | 1640 else (); |
1612 return_code | 1641 return_code |
1613 end | 1642 end |
1614 | 1643 |
1644 fun lock_project ({ context, libs } : project) = | |
1645 let val outcomes = map (fn lib => | |
1646 (#libname lib, AnyLibControl.id_of context lib)) | |
1647 libs | |
1648 val locks = | |
1649 List.concat | |
1650 (map (fn (libname, result) => | |
1651 case result of | |
1652 ERROR _ => [] | |
1653 | OK id => [{ libname = libname, id_or_tag = id }]) | |
1654 outcomes) | |
1655 val return_code = return_code_for outcomes | |
1656 val _ = print clear_line | |
1657 in | |
1658 if OS.Process.isSuccess return_code | |
1659 then save_lock_file (#rootpath context) locks | |
1660 else (); | |
1661 return_code | |
1662 end | |
1663 | |
1615 fun load_local_project pintype = | 1664 fun load_local_project pintype = |
1616 let val userconfig = load_userconfig () | 1665 let val userconfig = load_userconfig () |
1617 val rootpath = OS.FileSys.getDir () | 1666 val rootpath = OS.FileSys.getDir () |
1618 in | 1667 in |
1619 load_project userconfig rootpath pintype | 1668 load_project userconfig rootpath pintype |
1628 val _ = print "\n"; | 1677 val _ = print "\n"; |
1629 in | 1678 in |
1630 return_code | 1679 return_code |
1631 end | 1680 end |
1632 | 1681 |
1633 fun review () = with_local_project NO_LOCKFILE review_project | 1682 fun review () = with_local_project USE_LOCKFILE review_project |
1634 fun status () = with_local_project NO_LOCKFILE status_of_project | 1683 fun status () = with_local_project USE_LOCKFILE status_of_project |
1635 fun update () = with_local_project NO_LOCKFILE update_project | 1684 fun update () = with_local_project NO_LOCKFILE update_project |
1685 fun lock () = with_local_project NO_LOCKFILE lock_project | |
1636 fun install () = with_local_project USE_LOCKFILE update_project | 1686 fun install () = with_local_project USE_LOCKFILE update_project |
1637 | 1687 |
1638 fun version () = | 1688 fun version () = |
1639 (print ("v" ^ vext_version ^ "\n"); | 1689 (print ("v" ^ vext_version ^ "\n"); |
1640 OS.Process.success) | 1690 OS.Process.success) |
1648 ^ "where <command> is one of:\n\n" | 1698 ^ "where <command> is one of:\n\n" |
1649 ^ " status print quick report on local status only, without using network\n" | 1699 ^ " status print quick report on local status only, without using network\n" |
1650 ^ " review check configured libraries against their providers, and report\n" | 1700 ^ " review check configured libraries against their providers, and report\n" |
1651 ^ " install update configured libraries according to project specs and lock file\n" | 1701 ^ " install update configured libraries according to project specs and lock file\n" |
1652 ^ " update update configured libraries and lock file according to project specs\n" | 1702 ^ " update update configured libraries and lock file according to project specs\n" |
1703 ^ " lock update lock file to match local library status\n" | |
1653 ^ " version print the Vext version number and exit\n\n"); | 1704 ^ " version print the Vext version number and exit\n\n"); |
1654 OS.Process.failure) | 1705 OS.Process.failure) |
1655 | 1706 |
1656 fun vext args = | 1707 fun vext args = |
1657 let val return_code = | 1708 let val return_code = |
1658 case args of | 1709 case args of |
1659 ["review"] => review () | 1710 ["review"] => review () |
1660 | ["status"] => status () | 1711 | ["status"] => status () |
1661 | ["install"] => install () | 1712 | ["install"] => install () |
1662 | ["update"] => update () | 1713 | ["update"] => update () |
1714 | ["lock"] => lock () | |
1663 | ["version"] => version () | 1715 | ["version"] => version () |
1664 | _ => usage () | 1716 | _ => usage () |
1665 in | 1717 in |
1666 OS.Process.exit return_code; | 1718 OS.Process.exit return_code; |
1667 () | 1719 () |