Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Reworked the "touch" command to be able to handle non-glob filenames. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
1b49ab3c6c414a2cf76eab1acb0a72dc |
User & Date: | stephan 2019-06-13 20:12:00 |
Context
2019-06-13
| ||
20:20 | Reworded misleading statements in the "touch" help. check-in: ad275f97 user: stephan tags: trunk | |
20:12 | Reworked the "touch" command to be able to handle non-glob filenames. check-in: 1b49ab3c user: stephan tags: trunk | |
14:10 | Update the built-in SQLite to the latest 3.29.0 alpha that includes compiler warning fixes. check-in: 7b7f5df8 user: drh tags: trunk | |
Changes
Changes to src/file.c.
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 |
usage("NAME [GLOB] [-nodots]"); } zDir = g.argv[2]; zGlob = g.argc==4 ? g.argv[3] : 0; fossil_print("%d\n", file_directory_size(zDir, zGlob, omitDotFiles)); } /* ** COMMAND: touch* ** ** Usage: %fossil touch ?OPTIONS? ** ** For each file in the current checkout matching one of the provided ** list of glob patterns, or all files if no globs are provided, sets ** the file's mtime to the time of the last checkin which modified ** that file. ** ** This command gets its name from the conventional Unix "touch" ** command. ** ** Options: ** --now Stamp each affected file with the current time. ** This is the default behavior. ** -c|--checkin Stamp each affected file with the time of the ** most recent checkin which modified that file. ** -g GLOBLIST Comma-separated list of glob patterns. Default ** is to touch all SCM-controlled files. ** -G GLOBFILE Similar to -g but reads its globs from a ** fossil-conventional glob list file. ** -v|-verbose Outputs information about its globs and each ** file it touches. ** -n|--dry-run Outputs which files would require touching, ** but does not touch them. ** ** Only one of -g or -G may be used. If neither is provided, ** the effect is as if a glob of '*' were provided. ** ** Only one of --now and --checkin may be used. The default ** is --now. ** */ void touch_cmd(){ const char * zGlobList; /* -g List of glob patterns */ const char * zGlobFile; /* -G File of glob patterns */ Glob * pGlob = 0; /* List of glob patterns */ int verboseFlag; int dryRunFlag; int vid; /* Checkout version */ int changeCount = 0; /* Number of files touched */ int checkinFlag; /* -c|--checkin */ i64 const nowTime = time(0); Stmt q; verboseFlag = find_option("verbose","v",0)!=0; dryRunFlag = find_option("dry-run","n",0)!=0; zGlobList = find_option("glob", "g",1); zGlobFile = find_option("globfile", "G",1); checkinFlag = find_option("checkin","c",0)!=0; if(find_option("now",0,0)!=0 && checkinFlag!=0){ fossil_fatal("Options --checkin and --now may not be used together."); } if(zGlobList && zGlobFile){ fossil_fatal("Options -g and -G may not be used together."); } verify_all_options(); db_must_be_within_tree(); vid = db_lget_int("checkout", 0); if(vid==0){ fossil_fatal("Cannot determine checkout version."); } if(zGlobList){ pGlob = *zGlobList ? glob_create(zGlobList) : 0; }else if(zGlobFile){ Blob globs; blob_read_from_file(&globs, zGlobFile, ExtFILE); pGlob = glob_create( globs.aData ); blob_reset(&globs); } db_begin_transaction(); db_prepare(&q, "SELECT vfile.mrid, pathname " "FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid " "WHERE vid=%d", vid); if( pGlob && verboseFlag!=0 ){ int i; for(i=0; i<pGlob->nPattern; ++i){ fossil_print("glob: %s\n", pGlob->azPattern[i]); } } if( verboseFlag ){ if(checkinFlag){ fossil_print("Using mtime from most recent commit(s).\n"); }else{ fossil_print("Using current time.\n"); } } while(SQLITE_ROW==db_step(&q)){ const char * zName = db_column_text(&q, 1); int const fid = db_column_int(&q, 0); i64 newMtime = checkinFlag ? 0 : nowTime; i64 currentMtime; if(pGlob){ if(glob_match(pGlob, zName)==0) continue; } currentMtime = file_mtime(zName, 0); if( newMtime || mtime_of_manifest_file(vid, fid, &newMtime)==0 ){ if( currentMtime!=newMtime ){ ++changeCount; if( dryRunFlag!=0 ){ fossil_print( "dry-run: %s\n", zName ); }else{ file_set_mtime(zName, newMtime); if( verboseFlag!=0 ){ fossil_print( "touched %s\n", zName ); } } } } } db_finalize(&q); db_end_transaction(0); glob_free(pGlob); if( dryRunFlag!=0 ){ fossil_print("dry-run: would have touched %d file(s)\n", changeCount); }else if( verboseFlag!=0 ){ fossil_print("Touched %d file(s)\n", changeCount); } } |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > | | < < > > > > > | > > | | > > > > > | | < < < > > > > > | | > > > | > < < > | < > > > > > > > > > | > > > > | > > > > > > > > > > > > > > | < < < < < > | | | | > > > > > > > > > > > > > > > > > > > > > | < | > | < > > > | | | < > > | < | < < < < > | < | | > | > > > > > > > > > > > > > > > > > > > > > > > | > | < > > > > > > > > > > > > > > > > > > > > > > < > < > | | < |
1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 |
usage("NAME [GLOB] [-nodots]"); } zDir = g.argv[2]; zGlob = g.argc==4 ? g.argv[3] : 0; fossil_print("%d\n", file_directory_size(zDir, zGlob, omitDotFiles)); } /* ** Internal helper for touch_cmd(). zAbsName must be resolvable as-is ** to a file - this function does not expand/normalize it. i.e. it ** "really should" be an absolute path. zTreeName is strictly ** cosmetic: it is used when dryRunFlag or verboseFlag generate ** output. It is assumed to be a repo-relative or or subdir-relative ** filename. ** ** newMTime is the file's new timestamp (Unix epoch). ** ** Returns 1 if it sets zAbsName's mtime, 0 if it does not (indicating ** that the file already has that timestamp). Dies fatally if given an ** unresolvable filename. If dryRunFlag is true then it outputs the ** name of the file it would have timestamped but does not stamp the ** file. If verboseFlag is true, it outputs a message if the files ** timestamp is actually modified. */ static int touch_cmd_stamp_one_file(char const *zAbsName, char const *zTreeName, i64 newMtime, int dryRunFlag, int verboseFlag){ i64 const currentMtime = file_mtime(zAbsName, 0); if(currentMtime<0){ fossil_fatal("Cannot stat file: %s\n", zAbsName); }else if(currentMtime==newMtime){ return 0; }else if( dryRunFlag!=0 ){ fossil_print( "dry-run: %s\n", zTreeName ); }else{ file_set_mtime(zAbsName, newMtime); if( verboseFlag!=0 ){ fossil_print( "touched %s\n", zTreeName ); } } return 1; } /* ** Internal helper for touch_cmd(). If the given name is found in the ** given checkout version, which MUST be the checkout version ** currently populating the vfile table, the vfile.mrid value for the ** file is returned, else 0 is returned. zName must be resolvable ** as-is - this function performs neither expands nor normalizes it. */ static int touch_cmd_vfile_mrid( int vid, char const *zName ){ int mrid = 0; static Stmt q = empty_Stmt_m; db_static_prepare(&q, "SELECT vfile.mrid " "FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid " "WHERE vid=:vid AND pathname=:pathname %s", filename_collation()); db_bind_int(&q, ":vid", vid); db_bind_text(&q, ":pathname", zName); if(SQLITE_ROW==db_step(&q)){ mrid = db_column_int(&q, 0); } db_reset(&q); return mrid; } /* ** COMMAND: touch* ** ** Usage: %fossil touch ?OPTIONS? ?FILENAME...? ** ** For each file in the current checkout matching one of the provided ** list of glob patterns and/or file names, the file's mtime is ** updated to a value specified by one of the flags --checkout, ** --checkin, or --now. ** ** If neither glob patterns nor filenames are provided, it operates on ** all files managed by the currently checked-out version. ** ** This command gets its name from the conventional Unix "touch" ** command. ** ** Options: ** --now Stamp each affected file with the current time. ** This is the default behavior. ** -c|--checkin Stamp each affected file with the time of the ** most recent check-in which modified that file. ** -C|--checkout Stamp each affected file with the time of the ** currently-checked-out version. ** -g GLOBLIST Comma-separated list of glob patterns. Default ** is to touch all SCM-controlled files. ** -G GLOBFILE Similar to -g but reads its globs from a ** fossil-conventional glob list file. ** -v|-verbose Outputs extra information about its globs ** and each file it touches. ** -n|--dry-run Outputs which files would require touching, ** but does not touch them. ** -q|--quiet Suppress warnings when skipping unmanaged ** or out-of-tree files. ** ** Only one of --now, --checkin, and --checkout may be used. The ** default is --now. ** ** Only one of -g or -G may be used. If neither is provided and no ** additional filenames are provided, the effect is as if a glob of ** '*' were provided. Note that all glob patterns provided via these ** flags are always evaluated as if they are relative to the top of ** the source tree, not the current working (sub)directory. Filenames ** provided without these flags, on the other hand, are treated as ** relative to the current directory. ** */ void touch_cmd(){ const char * zGlobList; /* -g List of glob patterns */ const char * zGlobFile; /* -G File of glob patterns */ Glob * pGlob = 0; /* List of glob patterns */ int verboseFlag; int dryRunFlag; int vid; /* Checkout version */ int changeCount = 0; /* Number of files touched */ int quietFlag = 0; /* -q|--quiet */ int timeFlag; /* -1==--checkin, 1==--checkout, 0==--now */ i64 nowTime = 0; /* Timestamp of --now or --checkout */ Stmt q; Blob absBuffer = empty_blob; verboseFlag = find_option("verbose","v",0)!=0; quietFlag = find_option("quiet","q",0)!=0; dryRunFlag = find_option("dry-run","n",0)!=0 || find_option("dryrun",0,0)!=0; zGlobList = find_option("glob", "g",1); zGlobFile = find_option("globfile", "G",1); if(zGlobList && zGlobFile){ fossil_fatal("Options -g and -G may not be used together."); } { int const ci = (find_option("checkin","c",0) || find_option("check-in",0,0)) ? 1 : 0; int const co = find_option("checkout","C",0) ? 1 : 0; int const now = find_option("now",0,0) ? 1 : 0; if(ci + co + now > 1){ fossil_fatal("Options --checkin, --checkout, and --now may " "not be used together."); }else if(co){ timeFlag = 1; if(verboseFlag){ fossil_print("Timestamp = current checkout version.\n"); } }else if(ci){ timeFlag = -1; if(verboseFlag){ fossil_print("Timestamp = checkin in which each file was " "most recently modified.\n"); } }else{ timeFlag = 0; if(verboseFlag){ fossil_print("Timestamp = current system time.\n"); } } } verify_all_options(); db_must_be_within_tree(); vid = db_lget_int("checkout", 0); if(vid==0){ fossil_fatal("Cannot determine checkout version."); } if(zGlobList){ pGlob = *zGlobList ? glob_create(zGlobList) : 0; }else if(zGlobFile){ Blob globs = empty_blob; blob_read_from_file(&globs, zGlobFile, ExtFILE); pGlob = glob_create( globs.aData ); blob_reset(&globs); } if( pGlob && verboseFlag!=0 ){ int i; for(i=0; i<pGlob->nPattern; ++i){ fossil_print("glob: %s\n", pGlob->azPattern[i]); } } db_begin_transaction(); if(timeFlag==0){/*--now*/ nowTime = time(0); }else if(timeFlag>0){/*--checkout: get the checkout manifest's timestamp*/ assert(vid>0); nowTime = db_int64(-1, "SELECT CAST(strftime('%%s'," "(SELECT mtime FROM event WHERE objid=%d)" ") AS INTEGER)", vid); if(nowTime<0){ fossil_fatal("Could not determine out checkout version's time!"); } }else{ /* --checkin */ assert(0 == nowTime); } if((pGlob && pGlob->nPattern>0) || g.argc<3 /* no non-flag arguments */ ){ /* ** We have either globs or no trailing filenames (in which case an ** effective glob pattern of '*' is assumed). If there are neither ** globs nor filenames then we operate on all managed files. */ db_prepare(&q, "SELECT vfile.mrid, pathname " "FROM vfile LEFT JOIN blob ON vfile.mrid=blob.rid " "WHERE vid=%d", vid); while(SQLITE_ROW==db_step(&q)){ int const fid = db_column_int(&q, 0); const char * zName = db_column_text(&q, 1); i64 newMtime = nowTime; char const * zAbs = 0; /* absolute path */ absBuffer.nUsed = 0; assert(timeFlag<0 ? newMtime==0 : newMtime>0); if(pGlob){ if(glob_match(pGlob, zName)==0) continue; } blob_appendf( &absBuffer, "%s%s", g.zLocalRoot, zName ); zAbs = blob_str(&absBuffer); if( newMtime || mtime_of_manifest_file(vid, fid, &newMtime)==0 ){ changeCount += touch_cmd_stamp_one_file( zAbs, zName, newMtime, dryRunFlag, verboseFlag ); } } db_finalize(&q); } glob_free(pGlob); pGlob = 0; if(g.argc>2){ /* ** Trailing filenames on the command line. These require extra ** care to avoid modifying unmanaged or out-of-tree files and ** finding an associated --checkin timestamp. */ int i; Blob treeNameBuf = empty_blob; for( i = 2; i < g.argc; ++i, blob_reset(&treeNameBuf) ){ char const * zArg = g.argv[i]; char const * zTreeFile; /* repo-relative filename */ char const * zAbs; /* absolute filename */ i64 newMtime = nowTime; int nameCheck; int fid; /* vfile.mrid of file */ absBuffer.nUsed = 0; nameCheck = file_tree_name( zArg, &treeNameBuf, 0, 0 ); if(nameCheck==0){ if(quietFlag==0){ fossil_print("SKIPPING out-of-tree file: %s\n", zArg); } continue; } zTreeFile = blob_str(&treeNameBuf); fid = touch_cmd_vfile_mrid( vid, zTreeFile ); if(fid==0){ if(quietFlag==0){ fossil_print("SKIPPING unmanaged file: %s\n", zArg); } continue; } blob_appendf(&absBuffer, "%s%s", g.zLocalRoot, zTreeFile); zAbs = blob_str(&absBuffer); if(timeFlag<0){/*--checkin*/ if(mtime_of_manifest_file( vid, fid, &newMtime )!=0){ fossil_fatal("Could not resolve --checkin mtime of %s", zTreeFile); } }else{ assert(newMtime>0); } changeCount += touch_cmd_stamp_one_file( zAbs, zArg, newMtime, dryRunFlag, verboseFlag ); } } db_end_transaction(0); blob_reset(&absBuffer); if( dryRunFlag!=0 ){ fossil_print("dry-run: would have touched %d file(s)\n", changeCount); } fossil_print("Touched %d file(s)\n", changeCount); } |