Fossil SCM
Add branch ls --users to list users participating in branches.
Commit
4615e2072af5381adafdd95b7de76ca6aa03c068af524ced438a424c8a90d100
Parent
d66ccf646e34588…
1 file changed
+55
-4
+55
-4
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -278,10 +278,11 @@ | ||
| 278 | 278 | #define BRL_ORDERBY_MTIME 0x004 /* Sort by MTIME. (otherwise sort by name)*/ |
| 279 | 279 | #define BRL_REVERSE 0x008 /* Reverse the sort order */ |
| 280 | 280 | #define BRL_PRIVATE 0x010 /* Show only private branches */ |
| 281 | 281 | #define BRL_MERGED 0x020 /* Show only merged branches */ |
| 282 | 282 | #define BRL_UNMERGED 0x040 /* Show only unmerged branches */ |
| 283 | +#define BRL_LIST_USERS 0x080 /* Populate list of users participating */ | |
| 283 | 284 | |
| 284 | 285 | #endif /* INTERFACE */ |
| 285 | 286 | |
| 286 | 287 | /* |
| 287 | 288 | ** Prepare a query that will list branches. |
| @@ -308,11 +309,27 @@ | ||
| 308 | 309 | /* Ignore nLimitMRU if no chronological sort requested. */ |
| 309 | 310 | if( (brFlags & BRL_ORDERBY_MTIME)==0 ) nLimitMRU = 0; |
| 310 | 311 | /* Undocumented: invert negative values for nLimitMRU, so that command-line |
| 311 | 312 | ** arguments similar to `head -5' with "option numbers" are possible. */ |
| 312 | 313 | if( nLimitMRU<0 ) nLimitMRU = -nLimitMRU; |
| 313 | - blob_append_sql(&sql,"SELECT name, isprivate, mergeto FROM ("); /* OUTER QUERY */ | |
| 314 | + /* OUTER QUERY */ | |
| 315 | + blob_append_sql(&sql,"SELECT name, isprivate, mergeto,"); | |
| 316 | + if( brFlags & BRL_LIST_USERS ){ | |
| 317 | + blob_append_sql(&sql, | |
| 318 | + " (SELECT group_concat(user) FROM (" | |
| 319 | + " SELECT DISTINCT * FROM (" | |
| 320 | + " SELECT coalesce(euser,user) AS user" | |
| 321 | + " FROM event" | |
| 322 | + " WHERE type='ci' AND objid IN (" | |
| 323 | + " SELECT rid FROM tagxref WHERE value=name)" | |
| 324 | + " ORDER BY 1)))" | |
| 325 | + ); | |
| 326 | + }else{ | |
| 327 | + blob_append_sql(&sql, " NULL"); | |
| 328 | + } | |
| 329 | + blob_append_sql(&sql," FROM ("); | |
| 330 | + /* INNER QUERY */ | |
| 314 | 331 | switch( brFlags & BRL_OPEN_CLOSED_MASK ){ |
| 315 | 332 | case BRL_CLOSED_ONLY: { |
| 316 | 333 | blob_append_sql(&sql, |
| 317 | 334 | "SELECT name, isprivate, mtime, mergeto FROM tmp_brlist WHERE isclosed" |
| 318 | 335 | ); |
| @@ -627,12 +644,13 @@ | ||
| 627 | 644 | ** -m|--merged List branches merged into the current branch |
| 628 | 645 | ** -M|--unmerged List branches not merged into the current branch |
| 629 | 646 | ** -p List only private branches |
| 630 | 647 | ** -r Reverse the sort order |
| 631 | 648 | ** -t Show recently changed branches first |
| 632 | -** --username USER List only branches with check-ins by USER | |
| 633 | -** --self List only branches with check-ins by the current user | |
| 649 | +** --self List only branches where you participate | |
| 650 | +** --username USER List only branches where USER participate | |
| 651 | +** --users N List up to N users partipiating | |
| 634 | 652 | ** |
| 635 | 653 | ** The current branch is marked with an asterisk. Private branches are |
| 636 | 654 | ** marked with a hash sign. |
| 637 | 655 | ** |
| 638 | 656 | ** If GLOB is given, show only branches matching the pattern. |
| @@ -697,14 +715,17 @@ | ||
| 697 | 715 | } |
| 698 | 716 | }else if( strncmp(zCmd,"list",n)==0 || |
| 699 | 717 | strncmp(zCmd, "ls", n)==0 || |
| 700 | 718 | strcmp(zCmd, "lsh")==0 ){ |
| 701 | 719 | Stmt q; |
| 720 | + Blob txt = empty_blob; | |
| 702 | 721 | int vid; |
| 703 | 722 | char *zCurrent = 0; |
| 704 | 723 | const char *zBrNameGlob = 0; |
| 705 | 724 | const char *zUser = find_option("username",0,1); |
| 725 | + const char *zUsersOpt = find_option("users",0,1); | |
| 726 | + int nUsers = zUsersOpt ? atoi(zUsersOpt) : 0; | |
| 706 | 727 | int nLimit = 0; |
| 707 | 728 | int brFlags = BRL_OPEN_ONLY; |
| 708 | 729 | if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH; |
| 709 | 730 | if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY; |
| 710 | 731 | if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME; |
| @@ -721,41 +742,71 @@ | ||
| 721 | 742 | } |
| 722 | 743 | |
| 723 | 744 | if ( (brFlags & BRL_MERGED) && (brFlags & BRL_UNMERGED) ){ |
| 724 | 745 | fossil_fatal("flags --merged and --unmerged are mutually exclusive"); |
| 725 | 746 | } |
| 747 | + if( zUsersOpt ){ | |
| 748 | + if( nUsers <= 0) fossil_fatal("With --users, N must be positive"); | |
| 749 | + brFlags |= BRL_LIST_USERS; | |
| 750 | + } | |
| 726 | 751 | if( strcmp(zCmd, "lsh")==0 ){ |
| 727 | 752 | nLimit = 5; |
| 728 | 753 | if( g.argc>4 || (g.argc==4 && (nLimit = atoi(g.argv[3]))==0) ){ |
| 729 | 754 | fossil_fatal("the lsh subcommand allows one optional numeric argument"); |
| 730 | 755 | } |
| 731 | 756 | brFlags |= BRL_ORDERBY_MTIME; |
| 732 | 757 | }else{ |
| 758 | + if( (g.argc == 4 || g.argc == 5) | |
| 759 | + && fossil_strcmp(g.argv[g.argc-1], "--user") == 0 ){ | |
| 760 | + fossil_fatal("Missing argument for --user"); | |
| 761 | + } | |
| 733 | 762 | if( g.argc >= 4 ) zBrNameGlob = g.argv[3]; |
| 734 | 763 | } |
| 735 | 764 | |
| 736 | 765 | if( g.localOpen ){ |
| 737 | 766 | vid = db_lget_int("checkout", 0); |
| 738 | 767 | zCurrent = db_text(0, "SELECT value FROM tagxref" |
| 739 | 768 | " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); |
| 740 | 769 | } |
| 741 | 770 | branch_prepare_list_query(&q, brFlags, zBrNameGlob, nLimit, zUser); |
| 771 | + blob_init(&txt, 0, 0); | |
| 742 | 772 | while( db_step(&q)==SQLITE_ROW ){ |
| 743 | 773 | const char *zBr = db_column_text(&q, 0); |
| 744 | 774 | int isPriv = zCurrent!=0 && db_column_int(&q, 1)==1; |
| 745 | 775 | const char *zMergeTo = db_column_text(&q, 2); |
| 746 | 776 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 777 | + const char *zUsers = db_column_text(&q, 3); | |
| 747 | 778 | if( (brFlags & BRL_MERGED) && fossil_strcmp(zCurrent,zMergeTo)!=0 ){ |
| 748 | 779 | continue; |
| 749 | 780 | } |
| 750 | 781 | if( (brFlags & BRL_UNMERGED) && (fossil_strcmp(zCurrent,zMergeTo)==0 |
| 751 | 782 | || isCur) ){ |
| 752 | 783 | continue; |
| 753 | 784 | } |
| 754 | - fossil_print("%s%s%s\n", | |
| 785 | + blob_appendf(&txt, "%s%s%s", | |
| 755 | 786 | ( (brFlags & BRL_PRIVATE) ? " " : ( isPriv ? "#" : " ") ), |
| 756 | 787 | (isCur ? "* " : " "), zBr); |
| 788 | + if( nUsers ){ | |
| 789 | + char c; | |
| 790 | + const char *cp; | |
| 791 | + const char *pComma = 0; | |
| 792 | + int commas = 0; | |
| 793 | + for( cp = zUsers; ( c = *cp ) != 0; cp++ ){ | |
| 794 | + if( c == ',' ){ | |
| 795 | + commas++; | |
| 796 | + if( commas == nUsers ) pComma = cp; | |
| 797 | + } | |
| 798 | + } | |
| 799 | + if( pComma ){ | |
| 800 | + blob_appendf(&txt, " (%.*s,... %i more)", | |
| 801 | + pComma - zUsers, zUsers, commas + 1 - nUsers); | |
| 802 | + }else{ | |
| 803 | + blob_appendf(&txt, " (%s)", zUsers); | |
| 804 | + } | |
| 805 | + } | |
| 806 | + fossil_print("%s\n", blob_str(&txt)); | |
| 807 | + blob_reset(&txt); | |
| 757 | 808 | } |
| 758 | 809 | db_finalize(&q); |
| 759 | 810 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 760 | 811 | branch_new(); |
| 761 | 812 | }else if( strncmp(zCmd,"close",5)==0 ){ |
| 762 | 813 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -278,10 +278,11 @@ | |
| 278 | #define BRL_ORDERBY_MTIME 0x004 /* Sort by MTIME. (otherwise sort by name)*/ |
| 279 | #define BRL_REVERSE 0x008 /* Reverse the sort order */ |
| 280 | #define BRL_PRIVATE 0x010 /* Show only private branches */ |
| 281 | #define BRL_MERGED 0x020 /* Show only merged branches */ |
| 282 | #define BRL_UNMERGED 0x040 /* Show only unmerged branches */ |
| 283 | |
| 284 | #endif /* INTERFACE */ |
| 285 | |
| 286 | /* |
| 287 | ** Prepare a query that will list branches. |
| @@ -308,11 +309,27 @@ | |
| 308 | /* Ignore nLimitMRU if no chronological sort requested. */ |
| 309 | if( (brFlags & BRL_ORDERBY_MTIME)==0 ) nLimitMRU = 0; |
| 310 | /* Undocumented: invert negative values for nLimitMRU, so that command-line |
| 311 | ** arguments similar to `head -5' with "option numbers" are possible. */ |
| 312 | if( nLimitMRU<0 ) nLimitMRU = -nLimitMRU; |
| 313 | blob_append_sql(&sql,"SELECT name, isprivate, mergeto FROM ("); /* OUTER QUERY */ |
| 314 | switch( brFlags & BRL_OPEN_CLOSED_MASK ){ |
| 315 | case BRL_CLOSED_ONLY: { |
| 316 | blob_append_sql(&sql, |
| 317 | "SELECT name, isprivate, mtime, mergeto FROM tmp_brlist WHERE isclosed" |
| 318 | ); |
| @@ -627,12 +644,13 @@ | |
| 627 | ** -m|--merged List branches merged into the current branch |
| 628 | ** -M|--unmerged List branches not merged into the current branch |
| 629 | ** -p List only private branches |
| 630 | ** -r Reverse the sort order |
| 631 | ** -t Show recently changed branches first |
| 632 | ** --username USER List only branches with check-ins by USER |
| 633 | ** --self List only branches with check-ins by the current user |
| 634 | ** |
| 635 | ** The current branch is marked with an asterisk. Private branches are |
| 636 | ** marked with a hash sign. |
| 637 | ** |
| 638 | ** If GLOB is given, show only branches matching the pattern. |
| @@ -697,14 +715,17 @@ | |
| 697 | } |
| 698 | }else if( strncmp(zCmd,"list",n)==0 || |
| 699 | strncmp(zCmd, "ls", n)==0 || |
| 700 | strcmp(zCmd, "lsh")==0 ){ |
| 701 | Stmt q; |
| 702 | int vid; |
| 703 | char *zCurrent = 0; |
| 704 | const char *zBrNameGlob = 0; |
| 705 | const char *zUser = find_option("username",0,1); |
| 706 | int nLimit = 0; |
| 707 | int brFlags = BRL_OPEN_ONLY; |
| 708 | if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH; |
| 709 | if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY; |
| 710 | if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME; |
| @@ -721,41 +742,71 @@ | |
| 721 | } |
| 722 | |
| 723 | if ( (brFlags & BRL_MERGED) && (brFlags & BRL_UNMERGED) ){ |
| 724 | fossil_fatal("flags --merged and --unmerged are mutually exclusive"); |
| 725 | } |
| 726 | if( strcmp(zCmd, "lsh")==0 ){ |
| 727 | nLimit = 5; |
| 728 | if( g.argc>4 || (g.argc==4 && (nLimit = atoi(g.argv[3]))==0) ){ |
| 729 | fossil_fatal("the lsh subcommand allows one optional numeric argument"); |
| 730 | } |
| 731 | brFlags |= BRL_ORDERBY_MTIME; |
| 732 | }else{ |
| 733 | if( g.argc >= 4 ) zBrNameGlob = g.argv[3]; |
| 734 | } |
| 735 | |
| 736 | if( g.localOpen ){ |
| 737 | vid = db_lget_int("checkout", 0); |
| 738 | zCurrent = db_text(0, "SELECT value FROM tagxref" |
| 739 | " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); |
| 740 | } |
| 741 | branch_prepare_list_query(&q, brFlags, zBrNameGlob, nLimit, zUser); |
| 742 | while( db_step(&q)==SQLITE_ROW ){ |
| 743 | const char *zBr = db_column_text(&q, 0); |
| 744 | int isPriv = zCurrent!=0 && db_column_int(&q, 1)==1; |
| 745 | const char *zMergeTo = db_column_text(&q, 2); |
| 746 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 747 | if( (brFlags & BRL_MERGED) && fossil_strcmp(zCurrent,zMergeTo)!=0 ){ |
| 748 | continue; |
| 749 | } |
| 750 | if( (brFlags & BRL_UNMERGED) && (fossil_strcmp(zCurrent,zMergeTo)==0 |
| 751 | || isCur) ){ |
| 752 | continue; |
| 753 | } |
| 754 | fossil_print("%s%s%s\n", |
| 755 | ( (brFlags & BRL_PRIVATE) ? " " : ( isPriv ? "#" : " ") ), |
| 756 | (isCur ? "* " : " "), zBr); |
| 757 | } |
| 758 | db_finalize(&q); |
| 759 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 760 | branch_new(); |
| 761 | }else if( strncmp(zCmd,"close",5)==0 ){ |
| 762 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -278,10 +278,11 @@ | |
| 278 | #define BRL_ORDERBY_MTIME 0x004 /* Sort by MTIME. (otherwise sort by name)*/ |
| 279 | #define BRL_REVERSE 0x008 /* Reverse the sort order */ |
| 280 | #define BRL_PRIVATE 0x010 /* Show only private branches */ |
| 281 | #define BRL_MERGED 0x020 /* Show only merged branches */ |
| 282 | #define BRL_UNMERGED 0x040 /* Show only unmerged branches */ |
| 283 | #define BRL_LIST_USERS 0x080 /* Populate list of users participating */ |
| 284 | |
| 285 | #endif /* INTERFACE */ |
| 286 | |
| 287 | /* |
| 288 | ** Prepare a query that will list branches. |
| @@ -308,11 +309,27 @@ | |
| 309 | /* Ignore nLimitMRU if no chronological sort requested. */ |
| 310 | if( (brFlags & BRL_ORDERBY_MTIME)==0 ) nLimitMRU = 0; |
| 311 | /* Undocumented: invert negative values for nLimitMRU, so that command-line |
| 312 | ** arguments similar to `head -5' with "option numbers" are possible. */ |
| 313 | if( nLimitMRU<0 ) nLimitMRU = -nLimitMRU; |
| 314 | /* OUTER QUERY */ |
| 315 | blob_append_sql(&sql,"SELECT name, isprivate, mergeto,"); |
| 316 | if( brFlags & BRL_LIST_USERS ){ |
| 317 | blob_append_sql(&sql, |
| 318 | " (SELECT group_concat(user) FROM (" |
| 319 | " SELECT DISTINCT * FROM (" |
| 320 | " SELECT coalesce(euser,user) AS user" |
| 321 | " FROM event" |
| 322 | " WHERE type='ci' AND objid IN (" |
| 323 | " SELECT rid FROM tagxref WHERE value=name)" |
| 324 | " ORDER BY 1)))" |
| 325 | ); |
| 326 | }else{ |
| 327 | blob_append_sql(&sql, " NULL"); |
| 328 | } |
| 329 | blob_append_sql(&sql," FROM ("); |
| 330 | /* INNER QUERY */ |
| 331 | switch( brFlags & BRL_OPEN_CLOSED_MASK ){ |
| 332 | case BRL_CLOSED_ONLY: { |
| 333 | blob_append_sql(&sql, |
| 334 | "SELECT name, isprivate, mtime, mergeto FROM tmp_brlist WHERE isclosed" |
| 335 | ); |
| @@ -627,12 +644,13 @@ | |
| 644 | ** -m|--merged List branches merged into the current branch |
| 645 | ** -M|--unmerged List branches not merged into the current branch |
| 646 | ** -p List only private branches |
| 647 | ** -r Reverse the sort order |
| 648 | ** -t Show recently changed branches first |
| 649 | ** --self List only branches where you participate |
| 650 | ** --username USER List only branches where USER participate |
| 651 | ** --users N List up to N users partipiating |
| 652 | ** |
| 653 | ** The current branch is marked with an asterisk. Private branches are |
| 654 | ** marked with a hash sign. |
| 655 | ** |
| 656 | ** If GLOB is given, show only branches matching the pattern. |
| @@ -697,14 +715,17 @@ | |
| 715 | } |
| 716 | }else if( strncmp(zCmd,"list",n)==0 || |
| 717 | strncmp(zCmd, "ls", n)==0 || |
| 718 | strcmp(zCmd, "lsh")==0 ){ |
| 719 | Stmt q; |
| 720 | Blob txt = empty_blob; |
| 721 | int vid; |
| 722 | char *zCurrent = 0; |
| 723 | const char *zBrNameGlob = 0; |
| 724 | const char *zUser = find_option("username",0,1); |
| 725 | const char *zUsersOpt = find_option("users",0,1); |
| 726 | int nUsers = zUsersOpt ? atoi(zUsersOpt) : 0; |
| 727 | int nLimit = 0; |
| 728 | int brFlags = BRL_OPEN_ONLY; |
| 729 | if( find_option("all","a",0)!=0 ) brFlags = BRL_BOTH; |
| 730 | if( find_option("closed","c",0)!=0 ) brFlags = BRL_CLOSED_ONLY; |
| 731 | if( find_option("t",0,0)!=0 ) brFlags |= BRL_ORDERBY_MTIME; |
| @@ -721,41 +742,71 @@ | |
| 742 | } |
| 743 | |
| 744 | if ( (brFlags & BRL_MERGED) && (brFlags & BRL_UNMERGED) ){ |
| 745 | fossil_fatal("flags --merged and --unmerged are mutually exclusive"); |
| 746 | } |
| 747 | if( zUsersOpt ){ |
| 748 | if( nUsers <= 0) fossil_fatal("With --users, N must be positive"); |
| 749 | brFlags |= BRL_LIST_USERS; |
| 750 | } |
| 751 | if( strcmp(zCmd, "lsh")==0 ){ |
| 752 | nLimit = 5; |
| 753 | if( g.argc>4 || (g.argc==4 && (nLimit = atoi(g.argv[3]))==0) ){ |
| 754 | fossil_fatal("the lsh subcommand allows one optional numeric argument"); |
| 755 | } |
| 756 | brFlags |= BRL_ORDERBY_MTIME; |
| 757 | }else{ |
| 758 | if( (g.argc == 4 || g.argc == 5) |
| 759 | && fossil_strcmp(g.argv[g.argc-1], "--user") == 0 ){ |
| 760 | fossil_fatal("Missing argument for --user"); |
| 761 | } |
| 762 | if( g.argc >= 4 ) zBrNameGlob = g.argv[3]; |
| 763 | } |
| 764 | |
| 765 | if( g.localOpen ){ |
| 766 | vid = db_lget_int("checkout", 0); |
| 767 | zCurrent = db_text(0, "SELECT value FROM tagxref" |
| 768 | " WHERE rid=%d AND tagid=%d", vid, TAG_BRANCH); |
| 769 | } |
| 770 | branch_prepare_list_query(&q, brFlags, zBrNameGlob, nLimit, zUser); |
| 771 | blob_init(&txt, 0, 0); |
| 772 | while( db_step(&q)==SQLITE_ROW ){ |
| 773 | const char *zBr = db_column_text(&q, 0); |
| 774 | int isPriv = zCurrent!=0 && db_column_int(&q, 1)==1; |
| 775 | const char *zMergeTo = db_column_text(&q, 2); |
| 776 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 777 | const char *zUsers = db_column_text(&q, 3); |
| 778 | if( (brFlags & BRL_MERGED) && fossil_strcmp(zCurrent,zMergeTo)!=0 ){ |
| 779 | continue; |
| 780 | } |
| 781 | if( (brFlags & BRL_UNMERGED) && (fossil_strcmp(zCurrent,zMergeTo)==0 |
| 782 | || isCur) ){ |
| 783 | continue; |
| 784 | } |
| 785 | blob_appendf(&txt, "%s%s%s", |
| 786 | ( (brFlags & BRL_PRIVATE) ? " " : ( isPriv ? "#" : " ") ), |
| 787 | (isCur ? "* " : " "), zBr); |
| 788 | if( nUsers ){ |
| 789 | char c; |
| 790 | const char *cp; |
| 791 | const char *pComma = 0; |
| 792 | int commas = 0; |
| 793 | for( cp = zUsers; ( c = *cp ) != 0; cp++ ){ |
| 794 | if( c == ',' ){ |
| 795 | commas++; |
| 796 | if( commas == nUsers ) pComma = cp; |
| 797 | } |
| 798 | } |
| 799 | if( pComma ){ |
| 800 | blob_appendf(&txt, " (%.*s,... %i more)", |
| 801 | pComma - zUsers, zUsers, commas + 1 - nUsers); |
| 802 | }else{ |
| 803 | blob_appendf(&txt, " (%s)", zUsers); |
| 804 | } |
| 805 | } |
| 806 | fossil_print("%s\n", blob_str(&txt)); |
| 807 | blob_reset(&txt); |
| 808 | } |
| 809 | db_finalize(&q); |
| 810 | }else if( strncmp(zCmd,"new",n)==0 ){ |
| 811 | branch_new(); |
| 812 | }else if( strncmp(zCmd,"close",5)==0 ){ |
| 813 |