Fossil SCM
New /file page that works like /artifact except takes a filename as an argument instead of a SHA1 hash of an artifact, and resolves to the most recent version of any file with that name.
Commit
d95f712f2caba1e268cfd33abfcdfe7b8122e32d
Parent
b9da89a44ed8e03…
1 file changed
+45
-20
+45
-20
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -1729,23 +1729,30 @@ | ||
| 1729 | 1729 | } |
| 1730 | 1730 | |
| 1731 | 1731 | /* |
| 1732 | 1732 | ** Look for "ci" and "filename" query parameters. If found, try to |
| 1733 | 1733 | ** use them to extract the record ID of an artifact for the file. |
| 1734 | +** | |
| 1735 | +** Also look for "fn" as an alias for "filename". If either "filename" | |
| 1736 | +** or "fn" is present but "ci" is missing, use "tip" as a default value | |
| 1737 | +** for "ci". | |
| 1734 | 1738 | */ |
| 1735 | 1739 | int artifact_from_ci_and_filename_www(void){ |
| 1736 | 1740 | const char *zFilename; |
| 1737 | 1741 | const char *zCI; |
| 1738 | 1742 | int cirid; |
| 1739 | 1743 | Manifest *pManifest; |
| 1740 | 1744 | ManifestFile *pFile; |
| 1741 | 1745 | |
| 1742 | - zCI = P("ci"); | |
| 1743 | - if( zCI==0 ) return 0; | |
| 1744 | 1746 | zFilename = P("filename"); |
| 1745 | - if( zFilename==0 ) return 0; | |
| 1746 | - cirid = name_to_rid_www("ci"); | |
| 1747 | + if( zFilename==0 ){ | |
| 1748 | + zFilename = P("fn"); | |
| 1749 | + if( zFilename==0 ) return 0; | |
| 1750 | + } | |
| 1751 | + zCI = PD("ci", "tip"); | |
| 1752 | + cirid = name_to_typed_rid(zCI, "ci"); | |
| 1753 | + if( cirid<=0 ) return 0; | |
| 1747 | 1754 | pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0); |
| 1748 | 1755 | if( pManifest==0 ) return 0; |
| 1749 | 1756 | manifest_file_rewind(pManifest); |
| 1750 | 1757 | while( (pFile = manifest_file_next(pManifest,0))!=0 ){ |
| 1751 | 1758 | if( fossil_strcmp(zFilename, pFile->zName)==0 ){ |
| @@ -1840,29 +1847,37 @@ | ||
| 1840 | 1847 | } |
| 1841 | 1848 | } |
| 1842 | 1849 | |
| 1843 | 1850 | |
| 1844 | 1851 | /* |
| 1845 | -** WEBPAGE: whatis | |
| 1846 | 1852 | ** WEBPAGE: artifact |
| 1853 | +** WEBPAGE: file | |
| 1854 | +** WEBPAGE: whatis | |
| 1855 | +** | |
| 1856 | +** Typical usage: | |
| 1847 | 1857 | ** |
| 1848 | -** URL: /artifact/SHA1HASH | |
| 1849 | -** URL: /artifact?ci=CHECKIN&filename=PATH | |
| 1850 | -** URL: /whatis/SHA1HASH | |
| 1858 | +** /artifact/SHA1HASH | |
| 1859 | +** /whatis/SHA1HASH | |
| 1860 | +** /file/NAME | |
| 1851 | 1861 | ** |
| 1852 | 1862 | ** Additional query parameters: |
| 1853 | 1863 | ** |
| 1854 | 1864 | ** ln - show line numbers |
| 1855 | 1865 | ** ln=N - highlight line number N |
| 1856 | 1866 | ** ln=M-N - highlight lines M through N inclusive |
| 1857 | 1867 | ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive) |
| 1858 | 1868 | ** verbose - show more detail in the description |
| 1859 | 1869 | ** download - redirect to the download (artifact page only) |
| 1870 | +** name=SHA1HASH - Provide the SHA1HASH as a query parameter | |
| 1871 | +** filename=NAME - Show information for content file NAME | |
| 1872 | +** fn=NAME - "fn" is shorthand for "filename" | |
| 1873 | +** ci=VERSION - The specific check-in to use for "filename=". | |
| 1860 | 1874 | ** |
| 1861 | 1875 | ** The /artifact page show the complete content of a file |
| 1862 | 1876 | ** identified by SHA1HASH as preformatted text. The |
| 1863 | -** /whatis page shows only a description of the file. | |
| 1877 | +** /whatis page shows only a description of the file. The /file | |
| 1878 | +** page shows the most recent version of the named file. | |
| 1864 | 1879 | */ |
| 1865 | 1880 | void artifact_page(void){ |
| 1866 | 1881 | int rid = 0; |
| 1867 | 1882 | Blob content; |
| 1868 | 1883 | const char *zMime; |
| @@ -1872,23 +1887,39 @@ | ||
| 1872 | 1887 | int objType; |
| 1873 | 1888 | int asText; |
| 1874 | 1889 | const char *zUuid; |
| 1875 | 1890 | u32 objdescFlags = 0; |
| 1876 | 1891 | int descOnly = fossil_strcmp(g.zPath,"whatis")==0; |
| 1892 | + int isFile = fossil_strcmp(g.zPath,"file")==0; | |
| 1877 | 1893 | const char *zLn = P("ln"); |
| 1878 | 1894 | |
| 1879 | - if( P("ci") && P("filename") ){ | |
| 1880 | - rid = artifact_from_ci_and_filename_www(); | |
| 1881 | - } | |
| 1895 | + rid = artifact_from_ci_and_filename_www(); | |
| 1882 | 1896 | if( rid==0 ){ |
| 1883 | - rid = name_to_rid_www("name"); | |
| 1897 | + if( fossil_strcmp(g.zPath,"file")==0 ){ | |
| 1898 | + rid = db_int(0, | |
| 1899 | + "SELECT fid FROM filename, mlink, event" | |
| 1900 | + " WHERE name=%Q" | |
| 1901 | + " AND mlink.fnid=filename.fnid" | |
| 1902 | + " AND event.objid=mlink.mid" | |
| 1903 | + " ORDER BY event.mtime DESC LIMIT 1", | |
| 1904 | + PD("name","") | |
| 1905 | + ); | |
| 1906 | + }else{ | |
| 1907 | + rid = name_to_rid_www("name"); | |
| 1908 | + } | |
| 1884 | 1909 | } |
| 1885 | 1910 | |
| 1886 | 1911 | login_check_credentials(); |
| 1887 | 1912 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1888 | 1913 | if( rid==0 ) fossil_redirect_home(); |
| 1889 | 1914 | if( descOnly || P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL; |
| 1915 | + zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 1916 | + if( g.perm.Setup ){ | |
| 1917 | + @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> | |
| 1918 | + }else{ | |
| 1919 | + @ <h2>Artifact %s(zUuid):</h2> | |
| 1920 | + } | |
| 1890 | 1921 | blob_zero(&downloadName); |
| 1891 | 1922 | objType = object_description(rid, objdescFlags, &downloadName); |
| 1892 | 1923 | if( !descOnly && P("download")!=0 ){ |
| 1893 | 1924 | cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName), |
| 1894 | 1925 | db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid)); |
| @@ -1902,16 +1933,10 @@ | ||
| 1902 | 1933 | }else{ |
| 1903 | 1934 | style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); |
| 1904 | 1935 | } |
| 1905 | 1936 | } |
| 1906 | 1937 | style_header("%s", descOnly ? "Artifact Description" : "Artifact Content"); |
| 1907 | - zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 1908 | - if( g.perm.Setup ){ | |
| 1909 | - @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> | |
| 1910 | - }else{ | |
| 1911 | - @ <h2>Artifact %s(zUuid):</h2> | |
| 1912 | - } | |
| 1913 | 1938 | if( g.perm.Admin ){ |
| 1914 | 1939 | Stmt q; |
| 1915 | 1940 | db_prepare(&q, |
| 1916 | 1941 | "SELECT coalesce(user.login,rcvfrom.uid)," |
| 1917 | 1942 | " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr" |
| @@ -1925,11 +1950,11 @@ | ||
| 1925 | 1950 | @ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p> |
| 1926 | 1951 | } |
| 1927 | 1952 | db_finalize(&q); |
| 1928 | 1953 | } |
| 1929 | 1954 | style_submenu_element("Download", "%R/raw/%T?name=%s", |
| 1930 | - blob_str(&downloadName), zUuid); | |
| 1955 | + blob_str(&downloadName), zUuid); | |
| 1931 | 1956 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 1932 | 1957 | style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid); |
| 1933 | 1958 | } |
| 1934 | 1959 | asText = P("txt")!=0; |
| 1935 | 1960 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1936 | 1961 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1729,23 +1729,30 @@ | |
| 1729 | } |
| 1730 | |
| 1731 | /* |
| 1732 | ** Look for "ci" and "filename" query parameters. If found, try to |
| 1733 | ** use them to extract the record ID of an artifact for the file. |
| 1734 | */ |
| 1735 | int artifact_from_ci_and_filename_www(void){ |
| 1736 | const char *zFilename; |
| 1737 | const char *zCI; |
| 1738 | int cirid; |
| 1739 | Manifest *pManifest; |
| 1740 | ManifestFile *pFile; |
| 1741 | |
| 1742 | zCI = P("ci"); |
| 1743 | if( zCI==0 ) return 0; |
| 1744 | zFilename = P("filename"); |
| 1745 | if( zFilename==0 ) return 0; |
| 1746 | cirid = name_to_rid_www("ci"); |
| 1747 | pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0); |
| 1748 | if( pManifest==0 ) return 0; |
| 1749 | manifest_file_rewind(pManifest); |
| 1750 | while( (pFile = manifest_file_next(pManifest,0))!=0 ){ |
| 1751 | if( fossil_strcmp(zFilename, pFile->zName)==0 ){ |
| @@ -1840,29 +1847,37 @@ | |
| 1840 | } |
| 1841 | } |
| 1842 | |
| 1843 | |
| 1844 | /* |
| 1845 | ** WEBPAGE: whatis |
| 1846 | ** WEBPAGE: artifact |
| 1847 | ** |
| 1848 | ** URL: /artifact/SHA1HASH |
| 1849 | ** URL: /artifact?ci=CHECKIN&filename=PATH |
| 1850 | ** URL: /whatis/SHA1HASH |
| 1851 | ** |
| 1852 | ** Additional query parameters: |
| 1853 | ** |
| 1854 | ** ln - show line numbers |
| 1855 | ** ln=N - highlight line number N |
| 1856 | ** ln=M-N - highlight lines M through N inclusive |
| 1857 | ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive) |
| 1858 | ** verbose - show more detail in the description |
| 1859 | ** download - redirect to the download (artifact page only) |
| 1860 | ** |
| 1861 | ** The /artifact page show the complete content of a file |
| 1862 | ** identified by SHA1HASH as preformatted text. The |
| 1863 | ** /whatis page shows only a description of the file. |
| 1864 | */ |
| 1865 | void artifact_page(void){ |
| 1866 | int rid = 0; |
| 1867 | Blob content; |
| 1868 | const char *zMime; |
| @@ -1872,23 +1887,39 @@ | |
| 1872 | int objType; |
| 1873 | int asText; |
| 1874 | const char *zUuid; |
| 1875 | u32 objdescFlags = 0; |
| 1876 | int descOnly = fossil_strcmp(g.zPath,"whatis")==0; |
| 1877 | const char *zLn = P("ln"); |
| 1878 | |
| 1879 | if( P("ci") && P("filename") ){ |
| 1880 | rid = artifact_from_ci_and_filename_www(); |
| 1881 | } |
| 1882 | if( rid==0 ){ |
| 1883 | rid = name_to_rid_www("name"); |
| 1884 | } |
| 1885 | |
| 1886 | login_check_credentials(); |
| 1887 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1888 | if( rid==0 ) fossil_redirect_home(); |
| 1889 | if( descOnly || P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL; |
| 1890 | blob_zero(&downloadName); |
| 1891 | objType = object_description(rid, objdescFlags, &downloadName); |
| 1892 | if( !descOnly && P("download")!=0 ){ |
| 1893 | cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName), |
| 1894 | db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid)); |
| @@ -1902,16 +1933,10 @@ | |
| 1902 | }else{ |
| 1903 | style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); |
| 1904 | } |
| 1905 | } |
| 1906 | style_header("%s", descOnly ? "Artifact Description" : "Artifact Content"); |
| 1907 | zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1908 | if( g.perm.Setup ){ |
| 1909 | @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> |
| 1910 | }else{ |
| 1911 | @ <h2>Artifact %s(zUuid):</h2> |
| 1912 | } |
| 1913 | if( g.perm.Admin ){ |
| 1914 | Stmt q; |
| 1915 | db_prepare(&q, |
| 1916 | "SELECT coalesce(user.login,rcvfrom.uid)," |
| 1917 | " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr" |
| @@ -1925,11 +1950,11 @@ | |
| 1925 | @ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p> |
| 1926 | } |
| 1927 | db_finalize(&q); |
| 1928 | } |
| 1929 | style_submenu_element("Download", "%R/raw/%T?name=%s", |
| 1930 | blob_str(&downloadName), zUuid); |
| 1931 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 1932 | style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid); |
| 1933 | } |
| 1934 | asText = P("txt")!=0; |
| 1935 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1936 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -1729,23 +1729,30 @@ | |
| 1729 | } |
| 1730 | |
| 1731 | /* |
| 1732 | ** Look for "ci" and "filename" query parameters. If found, try to |
| 1733 | ** use them to extract the record ID of an artifact for the file. |
| 1734 | ** |
| 1735 | ** Also look for "fn" as an alias for "filename". If either "filename" |
| 1736 | ** or "fn" is present but "ci" is missing, use "tip" as a default value |
| 1737 | ** for "ci". |
| 1738 | */ |
| 1739 | int artifact_from_ci_and_filename_www(void){ |
| 1740 | const char *zFilename; |
| 1741 | const char *zCI; |
| 1742 | int cirid; |
| 1743 | Manifest *pManifest; |
| 1744 | ManifestFile *pFile; |
| 1745 | |
| 1746 | zFilename = P("filename"); |
| 1747 | if( zFilename==0 ){ |
| 1748 | zFilename = P("fn"); |
| 1749 | if( zFilename==0 ) return 0; |
| 1750 | } |
| 1751 | zCI = PD("ci", "tip"); |
| 1752 | cirid = name_to_typed_rid(zCI, "ci"); |
| 1753 | if( cirid<=0 ) return 0; |
| 1754 | pManifest = manifest_get(cirid, CFTYPE_MANIFEST, 0); |
| 1755 | if( pManifest==0 ) return 0; |
| 1756 | manifest_file_rewind(pManifest); |
| 1757 | while( (pFile = manifest_file_next(pManifest,0))!=0 ){ |
| 1758 | if( fossil_strcmp(zFilename, pFile->zName)==0 ){ |
| @@ -1840,29 +1847,37 @@ | |
| 1847 | } |
| 1848 | } |
| 1849 | |
| 1850 | |
| 1851 | /* |
| 1852 | ** WEBPAGE: artifact |
| 1853 | ** WEBPAGE: file |
| 1854 | ** WEBPAGE: whatis |
| 1855 | ** |
| 1856 | ** Typical usage: |
| 1857 | ** |
| 1858 | ** /artifact/SHA1HASH |
| 1859 | ** /whatis/SHA1HASH |
| 1860 | ** /file/NAME |
| 1861 | ** |
| 1862 | ** Additional query parameters: |
| 1863 | ** |
| 1864 | ** ln - show line numbers |
| 1865 | ** ln=N - highlight line number N |
| 1866 | ** ln=M-N - highlight lines M through N inclusive |
| 1867 | ** ln=M-N+Y-Z - highlight lines M through N and Y through Z (inclusive) |
| 1868 | ** verbose - show more detail in the description |
| 1869 | ** download - redirect to the download (artifact page only) |
| 1870 | ** name=SHA1HASH - Provide the SHA1HASH as a query parameter |
| 1871 | ** filename=NAME - Show information for content file NAME |
| 1872 | ** fn=NAME - "fn" is shorthand for "filename" |
| 1873 | ** ci=VERSION - The specific check-in to use for "filename=". |
| 1874 | ** |
| 1875 | ** The /artifact page show the complete content of a file |
| 1876 | ** identified by SHA1HASH as preformatted text. The |
| 1877 | ** /whatis page shows only a description of the file. The /file |
| 1878 | ** page shows the most recent version of the named file. |
| 1879 | */ |
| 1880 | void artifact_page(void){ |
| 1881 | int rid = 0; |
| 1882 | Blob content; |
| 1883 | const char *zMime; |
| @@ -1872,23 +1887,39 @@ | |
| 1887 | int objType; |
| 1888 | int asText; |
| 1889 | const char *zUuid; |
| 1890 | u32 objdescFlags = 0; |
| 1891 | int descOnly = fossil_strcmp(g.zPath,"whatis")==0; |
| 1892 | int isFile = fossil_strcmp(g.zPath,"file")==0; |
| 1893 | const char *zLn = P("ln"); |
| 1894 | |
| 1895 | rid = artifact_from_ci_and_filename_www(); |
| 1896 | if( rid==0 ){ |
| 1897 | if( fossil_strcmp(g.zPath,"file")==0 ){ |
| 1898 | rid = db_int(0, |
| 1899 | "SELECT fid FROM filename, mlink, event" |
| 1900 | " WHERE name=%Q" |
| 1901 | " AND mlink.fnid=filename.fnid" |
| 1902 | " AND event.objid=mlink.mid" |
| 1903 | " ORDER BY event.mtime DESC LIMIT 1", |
| 1904 | PD("name","") |
| 1905 | ); |
| 1906 | }else{ |
| 1907 | rid = name_to_rid_www("name"); |
| 1908 | } |
| 1909 | } |
| 1910 | |
| 1911 | login_check_credentials(); |
| 1912 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 1913 | if( rid==0 ) fossil_redirect_home(); |
| 1914 | if( descOnly || P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL; |
| 1915 | zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 1916 | if( g.perm.Setup ){ |
| 1917 | @ <h2>Artifact %s(zUuid) (%d(rid)):</h2> |
| 1918 | }else{ |
| 1919 | @ <h2>Artifact %s(zUuid):</h2> |
| 1920 | } |
| 1921 | blob_zero(&downloadName); |
| 1922 | objType = object_description(rid, objdescFlags, &downloadName); |
| 1923 | if( !descOnly && P("download")!=0 ){ |
| 1924 | cgi_redirectf("%R/raw/%T?name=%s", blob_str(&downloadName), |
| 1925 | db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid)); |
| @@ -1902,16 +1933,10 @@ | |
| 1933 | }else{ |
| 1934 | style_submenu_element("Shun", "%s/shun?shun=%s#addshun", g.zTop, zUuid); |
| 1935 | } |
| 1936 | } |
| 1937 | style_header("%s", descOnly ? "Artifact Description" : "Artifact Content"); |
| 1938 | if( g.perm.Admin ){ |
| 1939 | Stmt q; |
| 1940 | db_prepare(&q, |
| 1941 | "SELECT coalesce(user.login,rcvfrom.uid)," |
| 1942 | " datetime(rcvfrom.mtime,toLocal()), rcvfrom.ipaddr" |
| @@ -1925,11 +1950,11 @@ | |
| 1950 | @ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p> |
| 1951 | } |
| 1952 | db_finalize(&q); |
| 1953 | } |
| 1954 | style_submenu_element("Download", "%R/raw/%T?name=%s", |
| 1955 | blob_str(&downloadName), zUuid); |
| 1956 | if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ |
| 1957 | style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid); |
| 1958 | } |
| 1959 | asText = P("txt")!=0; |
| 1960 | zMime = mimetype_from_name(blob_str(&downloadName)); |
| 1961 |