Fossil SCM
Enhance the "fossil timeline" command so that one can specify a file or directory as a command-line argument and the timeline only shows check-ins that involve that particular file or any of the files in the named directory.
Commit
e05a74f1f471272261a0ffde7f463f5aa39e0878
Parent
b8b037610f7f717…
1 file changed
+74
-39
+74
-39
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -1655,11 +1655,10 @@ | ||
| 1655 | 1655 | /* |
| 1656 | 1656 | ** Return a pointer to a static string that forms the basis for |
| 1657 | 1657 | ** a timeline query for display on a TTY. |
| 1658 | 1658 | */ |
| 1659 | 1659 | const char *timeline_query_for_tty(void){ |
| 1660 | - static const char *zBase = 0; | |
| 1661 | 1660 | static const char zBaseSql[] = |
| 1662 | 1661 | @ SELECT |
| 1663 | 1662 | @ blob.rid AS rid, |
| 1664 | 1663 | @ uuid, |
| 1665 | 1664 | @ datetime(event.mtime%s) AS mDateTime, |
| @@ -1675,20 +1674,17 @@ | ||
| 1675 | 1674 | @ AS primPlinkCount, |
| 1676 | 1675 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, |
| 1677 | 1676 | @ event.mtime AS mtime, |
| 1678 | 1677 | @ tagxref.value AS branch |
| 1679 | 1678 | @ FROM tag CROSS JOIN event CROSS JOIN blob |
| 1680 | - @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid | |
| 1679 | + @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid | |
| 1681 | 1680 | @ AND tagxref.tagtype>0 |
| 1682 | 1681 | @ AND tagxref.rid=blob.rid |
| 1683 | 1682 | @ WHERE blob.rid=event.objid |
| 1684 | 1683 | @ AND tag.tagname='branch' |
| 1685 | 1684 | ; |
| 1686 | - if( zBase==0 ){ | |
| 1687 | - zBase = mprintf(zBaseSql, timeline_utc()); | |
| 1688 | - } | |
| 1689 | - return zBase; | |
| 1685 | + return mprintf(zBaseSql, timeline_utc()); | |
| 1690 | 1686 | } |
| 1691 | 1687 | |
| 1692 | 1688 | /* |
| 1693 | 1689 | ** Return true if the input string is a date in the ISO 8601 format: |
| 1694 | 1690 | ** YYYY-MM-DD. |
| @@ -1739,11 +1735,11 @@ | ||
| 1739 | 1735 | ** -R REPO_FILE Specifies the repository db to use. Default is |
| 1740 | 1736 | ** the current checkout's repository. |
| 1741 | 1737 | */ |
| 1742 | 1738 | void timeline_cmd(void){ |
| 1743 | 1739 | Stmt q; |
| 1744 | - int n, k, width; | |
| 1740 | + int n, k, width, i; | |
| 1745 | 1741 | const char *zLimit; |
| 1746 | 1742 | const char *zWidth; |
| 1747 | 1743 | const char *zOffset; |
| 1748 | 1744 | const char *zType; |
| 1749 | 1745 | char *zOrigin; |
| @@ -1752,10 +1748,12 @@ | ||
| 1752 | 1748 | int objid = 0; |
| 1753 | 1749 | Blob uuid; |
| 1754 | 1750 | int mode = 0 ; /* 0:none 1: before 2:after 3:children 4:parents */ |
| 1755 | 1751 | int verboseFlag = 0 ; |
| 1756 | 1752 | int iOffset; |
| 1753 | + const char *zFilePattern = 0; | |
| 1754 | + Blob treeName; | |
| 1757 | 1755 | |
| 1758 | 1756 | verboseFlag = find_option("verbose","v", 0)!=0; |
| 1759 | 1757 | if( !verboseFlag){ |
| 1760 | 1758 | verboseFlag = find_option("showfiles","f", 0)!=0; /* deprecated */ |
| 1761 | 1759 | } |
| @@ -1783,37 +1781,39 @@ | ||
| 1783 | 1781 | iOffset = zOffset ? atoi(zOffset) : 0; |
| 1784 | 1782 | |
| 1785 | 1783 | /* We should be done with options.. */ |
| 1786 | 1784 | verify_all_options(); |
| 1787 | 1785 | |
| 1788 | - if( g.argc>=4 ){ | |
| 1789 | - k = strlen(g.argv[2]); | |
| 1790 | - if( strncmp(g.argv[2],"before",k)==0 ){ | |
| 1791 | - mode = 1; | |
| 1792 | - }else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){ | |
| 1793 | - mode = 2; | |
| 1794 | - }else if( strncmp(g.argv[2],"descendants",k)==0 ){ | |
| 1795 | - mode = 3; | |
| 1796 | - }else if( strncmp(g.argv[2],"children",k)==0 ){ | |
| 1797 | - mode = 3; | |
| 1798 | - }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){ | |
| 1799 | - mode = 4; | |
| 1800 | - }else if( strncmp(g.argv[2],"parents",k)==0 ){ | |
| 1801 | - mode = 4; | |
| 1802 | - }else if(!zType && !zLimit){ | |
| 1803 | - usage("?WHEN? ?BASELINE|DATETIME? ?-n|--limit #? ?-t|--type TYPE? " | |
| 1804 | - "?-W|--width WIDTH?"); | |
| 1805 | - } | |
| 1806 | - if( '-' != *g.argv[3] ){ | |
| 1807 | - zOrigin = g.argv[3]; | |
| 1808 | - }else{ | |
| 1809 | - zOrigin = "now"; | |
| 1810 | - } | |
| 1811 | - }else if( g.argc==3 ){ | |
| 1812 | - zOrigin = g.argv[2]; | |
| 1813 | - }else{ | |
| 1814 | - zOrigin = "now"; | |
| 1786 | + zOrigin = "now"; | |
| 1787 | + zFilePattern = 0; | |
| 1788 | + for(i=2; i<g.argc; i++){ | |
| 1789 | + char *zArg = g.argv[i]; | |
| 1790 | + k = strlen(zArg); | |
| 1791 | + if( mode==0 ){ | |
| 1792 | + if( strncmp(zArg,"before",k)==0 ){ | |
| 1793 | + mode = 1; | |
| 1794 | + }else if( strncmp(zArg,"after",k)==0 && k>1 ){ | |
| 1795 | + mode = 2; | |
| 1796 | + }else if( strncmp(zArg,"descendants",k)==0 ){ | |
| 1797 | + mode = 3; | |
| 1798 | + }else if( strncmp(zArg,"children",k)==0 ){ | |
| 1799 | + mode = 3; | |
| 1800 | + }else if( strncmp(zArg,"ancestors",k)==0 && k>1 ){ | |
| 1801 | + mode = 4; | |
| 1802 | + }else if( strncmp(zArg,"parents",k)==0 ){ | |
| 1803 | + mode = 4; | |
| 1804 | + } | |
| 1805 | + if( mode ){ | |
| 1806 | + if( i<g.argc-1 ) zOrigin = g.argv[++i]; | |
| 1807 | + continue; | |
| 1808 | + } | |
| 1809 | + } | |
| 1810 | + if( zFilePattern==0 ){ | |
| 1811 | + zFilePattern = zArg; | |
| 1812 | + }else{ | |
| 1813 | + usage("?WHEN? ?CHECKIN|DATETIME? ?FILE? ?OPTIONS?"); | |
| 1814 | + } | |
| 1815 | 1815 | } |
| 1816 | 1816 | k = strlen(zOrigin); |
| 1817 | 1817 | blob_zero(&uuid); |
| 1818 | 1818 | blob_append(&uuid, zOrigin, -1); |
| 1819 | 1819 | if( fossil_strcmp(zOrigin, "now")==0 ){ |
| @@ -1838,10 +1838,25 @@ | ||
| 1838 | 1838 | if( mode==0 ){ |
| 1839 | 1839 | if( isIsoDate(zOrigin) ) zShift = ",'+1 day'"; |
| 1840 | 1840 | } |
| 1841 | 1841 | zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift); |
| 1842 | 1842 | } |
| 1843 | + | |
| 1844 | + if( zFilePattern ){ | |
| 1845 | + if( zType==0 ){ | |
| 1846 | + /* When zFilePattern is specified and type is not specified, only show | |
| 1847 | + * file checkins */ | |
| 1848 | + zType="ci"; | |
| 1849 | + } | |
| 1850 | + file_tree_name(zFilePattern, &treeName, 1); | |
| 1851 | + if( fossil_strcmp(blob_str(&treeName), ".")==0 ){ | |
| 1852 | + /* When zTreeName refers to g.zLocalRoot, it's like not specifying | |
| 1853 | + * zFilePattern. */ | |
| 1854 | + zFilePattern = 0; | |
| 1855 | + } | |
| 1856 | + } | |
| 1857 | + | |
| 1843 | 1858 | if( mode==0 ) mode = 1; |
| 1844 | 1859 | blob_zero(&sql); |
| 1845 | 1860 | blob_append(&sql, timeline_query_for_tty(), -1); |
| 1846 | 1861 | blob_appendf(&sql, " AND event.mtime %s %s", |
| 1847 | 1862 | (mode==1 || mode==4) ? "<=" : ">=", |
| @@ -1853,22 +1868,42 @@ | ||
| 1853 | 1868 | if( mode==3 ){ |
| 1854 | 1869 | compute_descendants(objid, n); |
| 1855 | 1870 | }else{ |
| 1856 | 1871 | compute_ancestors(objid, n, 0); |
| 1857 | 1872 | } |
| 1858 | - blob_appendf(&sql, " AND blob.rid IN ok"); | |
| 1873 | + blob_appendf(&sql, "\n AND blob.rid IN ok"); | |
| 1859 | 1874 | } |
| 1860 | 1875 | if( zType && (zType[0]!='a') ){ |
| 1861 | - blob_appendf(&sql, " AND event.type=%Q ", zType); | |
| 1876 | + blob_appendf(&sql, "\n AND event.type=%Q ", zType); | |
| 1877 | + } | |
| 1878 | + if( zFilePattern ){ | |
| 1879 | + blob_append(&sql, | |
| 1880 | + "\n AND EXISTS(SELECT 1 FROM mlink\n" | |
| 1881 | + " WHERE mlink.mid=event.objid\n" | |
| 1882 | + " AND mlink.fnid IN ", -1); | |
| 1883 | + if( filenames_are_case_sensitive() ){ | |
| 1884 | + blob_appendf(&sql, | |
| 1885 | + "(SELECT fnid FROM filename" | |
| 1886 | + " WHERE name=%Q" | |
| 1887 | + " OR name GLOB '%q/*')", | |
| 1888 | + blob_str(&treeName), blob_str(&treeName)); | |
| 1889 | + }else{ | |
| 1890 | + blob_appendf(&sql, | |
| 1891 | + "(SELECT fnid FROM filename" | |
| 1892 | + " WHERE name=%Q COLLATE nocase" | |
| 1893 | + " OR lower(name) GLOB lower('%q/*'))", | |
| 1894 | + blob_str(&treeName), blob_str(&treeName)); | |
| 1895 | + } | |
| 1896 | + blob_append(&sql, ")", -1); | |
| 1862 | 1897 | } |
| 1863 | - blob_appendf(&sql, " ORDER BY event.mtime DESC"); | |
| 1898 | + blob_appendf(&sql, "\nORDER BY event.mtime DESC"); | |
| 1864 | 1899 | if( iOffset>0 ){ |
| 1865 | 1900 | /* Don't handle LIMIT here, otherwise print_timeline() |
| 1866 | 1901 | * will not determine the end-marker correctly! */ |
| 1867 | - blob_appendf(&sql, " LIMIT -1 OFFSET %d", iOffset); | |
| 1902 | + blob_appendf(&sql, "\n LIMIT -1 OFFSET %d", iOffset); | |
| 1868 | 1903 | } |
| 1869 | - db_prepare(&q, blob_str(&sql)); | |
| 1904 | + db_prepare(&q, "%s", blob_str(&sql)); | |
| 1870 | 1905 | blob_reset(&sql); |
| 1871 | 1906 | print_timeline(&q, n, width, verboseFlag); |
| 1872 | 1907 | db_finalize(&q); |
| 1873 | 1908 | } |
| 1874 | 1909 | |
| 1875 | 1910 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1655,11 +1655,10 @@ | |
| 1655 | /* |
| 1656 | ** Return a pointer to a static string that forms the basis for |
| 1657 | ** a timeline query for display on a TTY. |
| 1658 | */ |
| 1659 | const char *timeline_query_for_tty(void){ |
| 1660 | static const char *zBase = 0; |
| 1661 | static const char zBaseSql[] = |
| 1662 | @ SELECT |
| 1663 | @ blob.rid AS rid, |
| 1664 | @ uuid, |
| 1665 | @ datetime(event.mtime%s) AS mDateTime, |
| @@ -1675,20 +1674,17 @@ | |
| 1675 | @ AS primPlinkCount, |
| 1676 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, |
| 1677 | @ event.mtime AS mtime, |
| 1678 | @ tagxref.value AS branch |
| 1679 | @ FROM tag CROSS JOIN event CROSS JOIN blob |
| 1680 | @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid |
| 1681 | @ AND tagxref.tagtype>0 |
| 1682 | @ AND tagxref.rid=blob.rid |
| 1683 | @ WHERE blob.rid=event.objid |
| 1684 | @ AND tag.tagname='branch' |
| 1685 | ; |
| 1686 | if( zBase==0 ){ |
| 1687 | zBase = mprintf(zBaseSql, timeline_utc()); |
| 1688 | } |
| 1689 | return zBase; |
| 1690 | } |
| 1691 | |
| 1692 | /* |
| 1693 | ** Return true if the input string is a date in the ISO 8601 format: |
| 1694 | ** YYYY-MM-DD. |
| @@ -1739,11 +1735,11 @@ | |
| 1739 | ** -R REPO_FILE Specifies the repository db to use. Default is |
| 1740 | ** the current checkout's repository. |
| 1741 | */ |
| 1742 | void timeline_cmd(void){ |
| 1743 | Stmt q; |
| 1744 | int n, k, width; |
| 1745 | const char *zLimit; |
| 1746 | const char *zWidth; |
| 1747 | const char *zOffset; |
| 1748 | const char *zType; |
| 1749 | char *zOrigin; |
| @@ -1752,10 +1748,12 @@ | |
| 1752 | int objid = 0; |
| 1753 | Blob uuid; |
| 1754 | int mode = 0 ; /* 0:none 1: before 2:after 3:children 4:parents */ |
| 1755 | int verboseFlag = 0 ; |
| 1756 | int iOffset; |
| 1757 | |
| 1758 | verboseFlag = find_option("verbose","v", 0)!=0; |
| 1759 | if( !verboseFlag){ |
| 1760 | verboseFlag = find_option("showfiles","f", 0)!=0; /* deprecated */ |
| 1761 | } |
| @@ -1783,37 +1781,39 @@ | |
| 1783 | iOffset = zOffset ? atoi(zOffset) : 0; |
| 1784 | |
| 1785 | /* We should be done with options.. */ |
| 1786 | verify_all_options(); |
| 1787 | |
| 1788 | if( g.argc>=4 ){ |
| 1789 | k = strlen(g.argv[2]); |
| 1790 | if( strncmp(g.argv[2],"before",k)==0 ){ |
| 1791 | mode = 1; |
| 1792 | }else if( strncmp(g.argv[2],"after",k)==0 && k>1 ){ |
| 1793 | mode = 2; |
| 1794 | }else if( strncmp(g.argv[2],"descendants",k)==0 ){ |
| 1795 | mode = 3; |
| 1796 | }else if( strncmp(g.argv[2],"children",k)==0 ){ |
| 1797 | mode = 3; |
| 1798 | }else if( strncmp(g.argv[2],"ancestors",k)==0 && k>1 ){ |
| 1799 | mode = 4; |
| 1800 | }else if( strncmp(g.argv[2],"parents",k)==0 ){ |
| 1801 | mode = 4; |
| 1802 | }else if(!zType && !zLimit){ |
| 1803 | usage("?WHEN? ?BASELINE|DATETIME? ?-n|--limit #? ?-t|--type TYPE? " |
| 1804 | "?-W|--width WIDTH?"); |
| 1805 | } |
| 1806 | if( '-' != *g.argv[3] ){ |
| 1807 | zOrigin = g.argv[3]; |
| 1808 | }else{ |
| 1809 | zOrigin = "now"; |
| 1810 | } |
| 1811 | }else if( g.argc==3 ){ |
| 1812 | zOrigin = g.argv[2]; |
| 1813 | }else{ |
| 1814 | zOrigin = "now"; |
| 1815 | } |
| 1816 | k = strlen(zOrigin); |
| 1817 | blob_zero(&uuid); |
| 1818 | blob_append(&uuid, zOrigin, -1); |
| 1819 | if( fossil_strcmp(zOrigin, "now")==0 ){ |
| @@ -1838,10 +1838,25 @@ | |
| 1838 | if( mode==0 ){ |
| 1839 | if( isIsoDate(zOrigin) ) zShift = ",'+1 day'"; |
| 1840 | } |
| 1841 | zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift); |
| 1842 | } |
| 1843 | if( mode==0 ) mode = 1; |
| 1844 | blob_zero(&sql); |
| 1845 | blob_append(&sql, timeline_query_for_tty(), -1); |
| 1846 | blob_appendf(&sql, " AND event.mtime %s %s", |
| 1847 | (mode==1 || mode==4) ? "<=" : ">=", |
| @@ -1853,22 +1868,42 @@ | |
| 1853 | if( mode==3 ){ |
| 1854 | compute_descendants(objid, n); |
| 1855 | }else{ |
| 1856 | compute_ancestors(objid, n, 0); |
| 1857 | } |
| 1858 | blob_appendf(&sql, " AND blob.rid IN ok"); |
| 1859 | } |
| 1860 | if( zType && (zType[0]!='a') ){ |
| 1861 | blob_appendf(&sql, " AND event.type=%Q ", zType); |
| 1862 | } |
| 1863 | blob_appendf(&sql, " ORDER BY event.mtime DESC"); |
| 1864 | if( iOffset>0 ){ |
| 1865 | /* Don't handle LIMIT here, otherwise print_timeline() |
| 1866 | * will not determine the end-marker correctly! */ |
| 1867 | blob_appendf(&sql, " LIMIT -1 OFFSET %d", iOffset); |
| 1868 | } |
| 1869 | db_prepare(&q, blob_str(&sql)); |
| 1870 | blob_reset(&sql); |
| 1871 | print_timeline(&q, n, width, verboseFlag); |
| 1872 | db_finalize(&q); |
| 1873 | } |
| 1874 | |
| 1875 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -1655,11 +1655,10 @@ | |
| 1655 | /* |
| 1656 | ** Return a pointer to a static string that forms the basis for |
| 1657 | ** a timeline query for display on a TTY. |
| 1658 | */ |
| 1659 | const char *timeline_query_for_tty(void){ |
| 1660 | static const char zBaseSql[] = |
| 1661 | @ SELECT |
| 1662 | @ blob.rid AS rid, |
| 1663 | @ uuid, |
| 1664 | @ datetime(event.mtime%s) AS mDateTime, |
| @@ -1675,20 +1674,17 @@ | |
| 1674 | @ AS primPlinkCount, |
| 1675 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) AS plinkCount, |
| 1676 | @ event.mtime AS mtime, |
| 1677 | @ tagxref.value AS branch |
| 1678 | @ FROM tag CROSS JOIN event CROSS JOIN blob |
| 1679 | @ LEFT JOIN tagxref ON tagxref.tagid=tag.tagid |
| 1680 | @ AND tagxref.tagtype>0 |
| 1681 | @ AND tagxref.rid=blob.rid |
| 1682 | @ WHERE blob.rid=event.objid |
| 1683 | @ AND tag.tagname='branch' |
| 1684 | ; |
| 1685 | return mprintf(zBaseSql, timeline_utc()); |
| 1686 | } |
| 1687 | |
| 1688 | /* |
| 1689 | ** Return true if the input string is a date in the ISO 8601 format: |
| 1690 | ** YYYY-MM-DD. |
| @@ -1739,11 +1735,11 @@ | |
| 1735 | ** -R REPO_FILE Specifies the repository db to use. Default is |
| 1736 | ** the current checkout's repository. |
| 1737 | */ |
| 1738 | void timeline_cmd(void){ |
| 1739 | Stmt q; |
| 1740 | int n, k, width, i; |
| 1741 | const char *zLimit; |
| 1742 | const char *zWidth; |
| 1743 | const char *zOffset; |
| 1744 | const char *zType; |
| 1745 | char *zOrigin; |
| @@ -1752,10 +1748,12 @@ | |
| 1748 | int objid = 0; |
| 1749 | Blob uuid; |
| 1750 | int mode = 0 ; /* 0:none 1: before 2:after 3:children 4:parents */ |
| 1751 | int verboseFlag = 0 ; |
| 1752 | int iOffset; |
| 1753 | const char *zFilePattern = 0; |
| 1754 | Blob treeName; |
| 1755 | |
| 1756 | verboseFlag = find_option("verbose","v", 0)!=0; |
| 1757 | if( !verboseFlag){ |
| 1758 | verboseFlag = find_option("showfiles","f", 0)!=0; /* deprecated */ |
| 1759 | } |
| @@ -1783,37 +1781,39 @@ | |
| 1781 | iOffset = zOffset ? atoi(zOffset) : 0; |
| 1782 | |
| 1783 | /* We should be done with options.. */ |
| 1784 | verify_all_options(); |
| 1785 | |
| 1786 | zOrigin = "now"; |
| 1787 | zFilePattern = 0; |
| 1788 | for(i=2; i<g.argc; i++){ |
| 1789 | char *zArg = g.argv[i]; |
| 1790 | k = strlen(zArg); |
| 1791 | if( mode==0 ){ |
| 1792 | if( strncmp(zArg,"before",k)==0 ){ |
| 1793 | mode = 1; |
| 1794 | }else if( strncmp(zArg,"after",k)==0 && k>1 ){ |
| 1795 | mode = 2; |
| 1796 | }else if( strncmp(zArg,"descendants",k)==0 ){ |
| 1797 | mode = 3; |
| 1798 | }else if( strncmp(zArg,"children",k)==0 ){ |
| 1799 | mode = 3; |
| 1800 | }else if( strncmp(zArg,"ancestors",k)==0 && k>1 ){ |
| 1801 | mode = 4; |
| 1802 | }else if( strncmp(zArg,"parents",k)==0 ){ |
| 1803 | mode = 4; |
| 1804 | } |
| 1805 | if( mode ){ |
| 1806 | if( i<g.argc-1 ) zOrigin = g.argv[++i]; |
| 1807 | continue; |
| 1808 | } |
| 1809 | } |
| 1810 | if( zFilePattern==0 ){ |
| 1811 | zFilePattern = zArg; |
| 1812 | }else{ |
| 1813 | usage("?WHEN? ?CHECKIN|DATETIME? ?FILE? ?OPTIONS?"); |
| 1814 | } |
| 1815 | } |
| 1816 | k = strlen(zOrigin); |
| 1817 | blob_zero(&uuid); |
| 1818 | blob_append(&uuid, zOrigin, -1); |
| 1819 | if( fossil_strcmp(zOrigin, "now")==0 ){ |
| @@ -1838,10 +1838,25 @@ | |
| 1838 | if( mode==0 ){ |
| 1839 | if( isIsoDate(zOrigin) ) zShift = ",'+1 day'"; |
| 1840 | } |
| 1841 | zDate = mprintf("(SELECT julianday(%Q%s, 'utc'))", zOrigin, zShift); |
| 1842 | } |
| 1843 | |
| 1844 | if( zFilePattern ){ |
| 1845 | if( zType==0 ){ |
| 1846 | /* When zFilePattern is specified and type is not specified, only show |
| 1847 | * file checkins */ |
| 1848 | zType="ci"; |
| 1849 | } |
| 1850 | file_tree_name(zFilePattern, &treeName, 1); |
| 1851 | if( fossil_strcmp(blob_str(&treeName), ".")==0 ){ |
| 1852 | /* When zTreeName refers to g.zLocalRoot, it's like not specifying |
| 1853 | * zFilePattern. */ |
| 1854 | zFilePattern = 0; |
| 1855 | } |
| 1856 | } |
| 1857 | |
| 1858 | if( mode==0 ) mode = 1; |
| 1859 | blob_zero(&sql); |
| 1860 | blob_append(&sql, timeline_query_for_tty(), -1); |
| 1861 | blob_appendf(&sql, " AND event.mtime %s %s", |
| 1862 | (mode==1 || mode==4) ? "<=" : ">=", |
| @@ -1853,22 +1868,42 @@ | |
| 1868 | if( mode==3 ){ |
| 1869 | compute_descendants(objid, n); |
| 1870 | }else{ |
| 1871 | compute_ancestors(objid, n, 0); |
| 1872 | } |
| 1873 | blob_appendf(&sql, "\n AND blob.rid IN ok"); |
| 1874 | } |
| 1875 | if( zType && (zType[0]!='a') ){ |
| 1876 | blob_appendf(&sql, "\n AND event.type=%Q ", zType); |
| 1877 | } |
| 1878 | if( zFilePattern ){ |
| 1879 | blob_append(&sql, |
| 1880 | "\n AND EXISTS(SELECT 1 FROM mlink\n" |
| 1881 | " WHERE mlink.mid=event.objid\n" |
| 1882 | " AND mlink.fnid IN ", -1); |
| 1883 | if( filenames_are_case_sensitive() ){ |
| 1884 | blob_appendf(&sql, |
| 1885 | "(SELECT fnid FROM filename" |
| 1886 | " WHERE name=%Q" |
| 1887 | " OR name GLOB '%q/*')", |
| 1888 | blob_str(&treeName), blob_str(&treeName)); |
| 1889 | }else{ |
| 1890 | blob_appendf(&sql, |
| 1891 | "(SELECT fnid FROM filename" |
| 1892 | " WHERE name=%Q COLLATE nocase" |
| 1893 | " OR lower(name) GLOB lower('%q/*'))", |
| 1894 | blob_str(&treeName), blob_str(&treeName)); |
| 1895 | } |
| 1896 | blob_append(&sql, ")", -1); |
| 1897 | } |
| 1898 | blob_appendf(&sql, "\nORDER BY event.mtime DESC"); |
| 1899 | if( iOffset>0 ){ |
| 1900 | /* Don't handle LIMIT here, otherwise print_timeline() |
| 1901 | * will not determine the end-marker correctly! */ |
| 1902 | blob_appendf(&sql, "\n LIMIT -1 OFFSET %d", iOffset); |
| 1903 | } |
| 1904 | db_prepare(&q, "%s", blob_str(&sql)); |
| 1905 | blob_reset(&sql); |
| 1906 | print_timeline(&q, n, width, verboseFlag); |
| 1907 | db_finalize(&q); |
| 1908 | } |
| 1909 | |
| 1910 |