Overview
SHA1 Hash: | c9fdb846fb169e3789256688942b56e5c4fa390f |
---|---|
Date: | 2007-08-18 02:45:47 |
User: | drh |
Comment: | Add the "help" command and the "clean" command. More work is needed on the text for various help messages. |
Timelines: | ancestors | descendants | both | trunk |
Other Links: | files | ZIP archive | manifest |
Tags And Properties
- branch=trunk inherited from [a28c83647d]
- sym-trunk inherited from [a28c83647d]
Changes
[hide diffs]Modified src/add.c from [f62f7b3cc4] to [771768ca0d].
@@ -30,12 +30,13 @@ /* ** COMMAND: add ** +** Usage: %fossil add FILE... ** Add one or more files to the current checkout such that these files -** will be added to the repository at the next checkin. +** will be inserted into the repository at the next commit. */ void add_cmd(void){ int i; int vid; @@ -80,10 +81,12 @@ /* ** COMMAND: rm ** COMMAND: del ** +** Usage: %fossil rm FILE... +** or: %fossil del FILE... ** Remove one or more files from the tree. */ void del_cmd(void){ int i; int vid;
Modified src/checkin.c from [2d5771221e] to [dfe4f317d7].
@@ -70,11 +70,13 @@ } /* ** COMMAND: changes ** -** Report on the current status of all files. +** Usage: %fossil changes +** Report on the edit status of all files in the current checkout. +** See also the "status" and "extra" commands. */ void changes_cmd(void){ Blob report; int vid; db_must_be_within_tree(); @@ -85,10 +87,12 @@ blob_write_to_file(&report, "-"); } /* ** COMMAND: status +** Usage: %fossil status +** Report on the status of the current checkout. */ void status_cmd(void){ int vid; db_must_be_within_tree(); /* 012345678901234 */ @@ -102,12 +106,12 @@ changes_cmd(); } /* ** COMMAND: ls -** -** Show all files currently in the repository +** Usage: %fossil ls +** Show the names of all files in the current checkout */ void ls_cmd(void){ int vid; Stmt q; @@ -134,29 +138,53 @@ db_finalize(&q); } /* ** COMMAND: extra -** +** Usage: %fossil extra ** Print a list of all files in the source tree that are not part of -** the project +** the current checkout. See also the "clean" command. */ void extra_cmd(void){ Blob path; Stmt q; db_must_be_within_tree(); db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); chdir(g.zLocalRoot); blob_zero(&path); vfile_scan(0, &path); - db_multi_exec("DELETE FROM sfile WHERE x='FOSSIL'"); db_prepare(&q, "SELECT x FROM sfile" " WHERE x NOT IN ('manifest','_FOSSIL_')" " ORDER BY 1"); while( db_step(&q)==SQLITE_ROW ){ printf("%s\n", db_column_text(&q, 0)); + } + db_finalize(&q); +} + +/* +** COMMAND: clean +** Usage: %fossil clean +** Delete all "extra" files in the source tree. "Extra" files are +** files that are not officially part of the checkout. See also +** the "extra" command. +*/ +void clean_cmd(void){ + Blob path; + Stmt q; + db_must_be_within_tree(); + db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); + chdir(g.zLocalRoot); + blob_zero(&path); + vfile_scan(0, &path); + db_prepare(&q, + "SELECT %Q || x FROM sfile" + " WHERE x NOT IN ('manifest','_FOSSIL_')" + " ORDER BY 1", g.zLocalRoot); + while( db_step(&q)==SQLITE_ROW ){ + unlink(db_column_text(&q, 0)); } db_finalize(&q); } /* @@ -191,10 +219,11 @@ } zFile = db_text(0, "SELECT '%qci-comment-' || hex(randomblob(6)) || '.txt'", g.zLocalRoot); blob_write_to_file(&text, zFile); zCmd = mprintf("%s %s", zEditor, zFile); + printf("%s\n", zCmd); if( system(zCmd) ){ fossil_panic("editor aborted"); } blob_reset(&text); blob_read_from_file(&text, zFile); @@ -255,17 +284,19 @@ } /* ** COMMAND: commit ** -** Create a new version containing all of the changes in the current -** checkout. A commit is a three step process: +** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...? ** -** 1) Add the new content to the blob table, -** 2) Create and add the new manifest to the blob table, -** 3) Update the vfile table, -** 4) Run checks to make sure everything is still internally consistent. +** Create a new version containing all of the changes in the current +** checkout. You will be prompted to enter a check-in comment unless +** the "-m" option is used to specify a command line. You will be +** prompted for your GPG passphrase in order to sign the new manifest +** unless the "--nosign" options is used. All files that have +** changed will be committed unless some subset of files is specified +** on the command line. */ void commit_cmd(void){ int rc; int vid, nrid, nvid; Blob comment;
Modified src/checkout.c from [ce6c20911d] to [ded735af90].
@@ -109,11 +109,16 @@ } /* ** COMMAND: checkout ** -** Check out a version specified on the command-line. +** Usage: %fossil checkout VERSION ?-f|--force? +** Check out a version specified on the command-line. This command +** will not overwrite edited files in the current checkout unless +** the --force option appears on the command-line. +** +** See also the "update" command. */ void checkout_cmd(void){ int forceFlag; int noWrite; int vid, prior; @@ -159,10 +164,11 @@ } /* ** COMMAND: close ** +** Usage: %fossil close ?-f|--force? ** The opposite of "open". Close the current database connection. ** Require a -f or --force flag if there are unsaved changed in the ** current check-out. */ void close_cmd(void){
Modified src/clone.c from [31346c860f] to [9c95e6e8e6].
@@ -30,13 +30,14 @@ /* ** COMMAND: clone ** -** Make a clone of a repository in the local directory +** Usage: %fossil clone URL FILENAME ** -** fossil clone FILE-OR-URL NEWDATABASE +** Make a clone of a repository specified by URL in the local +** file named FILENAME. */ void clone_cmd(void){ if( g.argc!=4 ){ usage("FILE-OR-URL NEW-REPOSITORY"); }
Modified src/db.c from [fafbfe094b] to [13dcb9659a].
@@ -103,12 +103,11 @@ /* ** Prepare or reprepare the sqlite3 statement from the raw SQL text. */ static void reprepare(Stmt *pStmt){ sqlite3_stmt *pNew; - int rc; - if( (rc = sqlite3_prepare(g.db, blob_buffer(&pStmt->sql), -1, &pNew, 0))!=0 ){ + if( sqlite3_prepare(g.db, blob_buffer(&pStmt->sql), -1, &pNew, 0)!=0 ){ db_err("%s\n%s", blob_str(&pStmt->sql), sqlite3_errmsg(g.db)); } if( pStmt->pStmt ){ sqlite3_transfer_bindings(pStmt->pStmt, pNew); sqlite3_finalize(pStmt->pStmt); @@ -191,11 +190,11 @@ /* ** Step the SQL statement. Return either SQLITE_ROW or an error code ** or SQLITE_OK if the statement finishes successfully. */ int db_step(Stmt *pStmt){ - int rc; + int rc = SQLITE_OK; int limit = 3; while( limit-- ){ rc = sqlite3_step(pStmt->pStmt); if( rc==SQLITE_ERROR ){ rc = sqlite3_reset(pStmt->pStmt); @@ -647,11 +646,14 @@ /* ** COMMAND: new ** -** Create a new repository +** Usage: %fossil new FILENAME +** Create a repository for a new project in the file named FILENAME. +** This command is distinct from "clone". The "clone" command makes +** a copy of an existing project. This command starts a new project. */ void create_repository_cmd(void){ char *zDate; char *zUser; Blob hash; @@ -821,11 +823,14 @@ } /* ** COMMAND: open ** -** Create a new local repository. +** Usage: open FILENAME +** Open a connection to the local repository in FILENAME. A checkout +** for the repository is created with its root at the working directory. +** See also the "close" command. */ void cmd_open(void){ Blob path; if( g.argc!=3 ){ usage("REPOSITORY-FILENAME");
Modified src/descendents.c from [caa863826b] to [6273899c23].
@@ -65,10 +65,11 @@ } /* ** COMMAND: leaves ** +** Usage: %fossil leaves ?UUID? ** Find all leaf descendents of the current version or of the ** specified version. */ void leaves_cmd(void){ Stmt q; @@ -94,23 +95,17 @@ } /* ** COMMAND: branches ** +** Usage: %fossil branches ** Find leaves of all branches. */ void branches_cmd(void){ Stmt q; - int base; db_must_be_within_tree(); - if( g.argc==2 ){ - base = db_lget_int("checkout", 0); - }else{ - base = name_to_rid(g.argv[2]); - } - if( base==0 ) return; db_prepare(&q, "SELECT blob.uuid, datetime(event.mtime,'localtime'), event.comment" " FROM blob, event" " WHERE blob.rid IN" " (SELECT cid FROM plink EXCEPT SELECT pid FROM plink)"
Modified src/diffcmd.c from [42f780093c] to [16a1f70543].
@@ -45,10 +45,15 @@ /* ** COMMAND: diff ** COMMAND: tkdiff +** +** Usage: %fossil diff|tkdiff FILE... +** Show the difference between the current version of a file (as it +** exists on disk) and that same file as it was checked out. Use +** either "diff -u" or "tkdiff". */ void diff_cmd(void){ const char *zFile; Blob cmd; Blob fname;
Modified src/main.c from [18f71690c1] to [69bfd961c8].
@@ -135,11 +135,11 @@ */ static int name_search( const char *zName, /* The name we are looking for */ const NameMap *aMap, /* Search in this array */ int nMap, /* Number of slots in aMap[] */ - void (**pxFunc)(void) /* Write pointer to handler function here */ + int *pIndex /* OUT: The index in aMap[] of the match */ ){ int upr, lwr, cnt, m, i; int n = strlen(zName); lwr = 0; upr = nMap-1; @@ -146,11 +146,11 @@ while( lwr<=upr ){ int mid, c; mid = (upr+lwr)/2; c = strcmp(zName, aMap[mid].zName); if( c==0 ){ - *pxFunc = aMap[mid].xFunc; + *pIndex = mid; return 0; }else if( c<0 ){ upr = mid - 1; }else{ lwr = mid + 1; @@ -162,11 +162,11 @@ m = i; cnt++; } } if( cnt==1 ){ - *pxFunc = aMap[m].xFunc; + *pIndex = m; return 0; } return 1+(cnt>1); } @@ -174,11 +174,11 @@ /* ** This procedure runs first. */ int main(int argc, char **argv){ const char *zCmdName; - void (*xFunc)(void); + int idx; int rc; g.now = time(0); g.argc = argc; g.argv = argv; @@ -192,11 +192,11 @@ g.fSqlPrint = find_option("sqlprint", 0, 0)!=0; g.fHttpTrace = find_option("httptrace", 0, 0)!=0; g.zLogin = find_option("user", "U", 1); zCmdName = argv[1]; } - rc = name_search(zCmdName, aCommand, count(aCommand), &xFunc); + rc = name_search(zCmdName, aCommand, count(aCommand), &idx); if( rc==1 ){ fprintf(stderr,"%s: unknown command: %s\n" "%s: use \"commands\" or \"test-commands\" for help\n", argv[0], zCmdName, argv[0]); return 1; @@ -204,11 +204,11 @@ fprintf(stderr,"%s: ambiguous command prefix: %s\n" "%s: use \"commands\" or \"test-commands\" for help\n", argv[0], zCmdName, argv[0]); return 1; } - xFunc(); + aCommand[idx].xFunc(); return 0; } /* ** Print an error message, rollback all databases, and quit. @@ -340,39 +340,78 @@ } /* ** COMMAND: commands ** -** List all commands whose name does not start with "test-" +** Usage: %fossil commands +** List all supported commands. */ void cmd_cmd_list(void){ int i, nCmd; const char *aCmd[count(aCommand)]; for(i=nCmd=0; i<count(aCommand); i++){ if( strncmp(aCommand[i].zName,"test",4)==0 ) continue; - if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; + /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */ aCmd[nCmd++] = aCommand[i].zName; } multi_column_list(aCmd, nCmd); } /* ** COMMAND: test-commands ** -** List all commands whose name begins with "test" +** Usage: %fossil test-commands +** List all commands used for testing and debugging. */ void cmd_test_cmd_list(void){ int i, nCmd; const char *aCmd[count(aCommand)]; for(i=nCmd=0; i<count(aCommand); i++){ if( strncmp(aCommand[i].zName,"test",4)!=0 ) continue; - if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; + /* if( strcmp(aCommand[i].zName, g.argv[1])==0 ) continue; */ aCmd[nCmd++] = aCommand[i].zName; } multi_column_list(aCmd, nCmd); } + +/* +** COMMAND: help +** +** Usage: %fossil help COMMAND +** Display information on how to use COMMAND +*/ +void help_cmd(void){ + int rc, idx; + const char *z; + if( g.argc!=3 ){ + printf("Usage: %s help <command>.\nAvailable commands:\n", g.argv[0]); + cmd_cmd_list(); + return; + } + rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); + if( rc==1 ){ + fossil_fatal("unknown command: %s", g.argv[2]); + }else if( rc==2 ){ + fossil_fatal("ambiguous command prefix: %s", g.argv[2]); + } + z = aCmdHelp[idx]; + if( z==0 ){ + fossil_fatal("no help available for the %s command", + aCommand[idx].zName); + } + while( *z ){ + if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ + printf("%s", g.argv[0]); + z += 7; + }else{ + putchar(*z); + z++; + } + } + putchar('\n'); +} /* ** RSS feeds need to reference absolute URLs so we need to calculate ** the base URL onto which we add components. This is basically ** cgi_redirect() stripped down and always returning an absolute URL. @@ -412,11 +451,11 @@ ** environment variable. */ static void process_one_web_page(void){ const char *zPathInfo; char *zPath; - void (*xFunc)(void); + int idx; int i, j; /* Find the page that the user has requested, construct and deliver that ** page. */ @@ -463,17 +502,17 @@ } /* Locate the method specified by the path and execute the function ** that implements that method. */ - if( name_search(g.zPath, aWebpage, count(aWebpage), &xFunc) && - name_search("not_found", aWebpage, count(aWebpage), &xFunc) ){ + if( name_search(g.zPath, aWebpage, count(aWebpage), &idx) && + name_search("not_found", aWebpage, count(aWebpage), &idx) ){ cgi_set_status(404,"Not Found"); @ <h1>Not Found</h1> @ <p>Page not found: %h(g.zPath)</p> }else{ - xFunc(); + aWebpage[idx].xFunc(); } /* Return the result. */ cgi_reply();
Modified src/mkindex.c from [a7cfef3b71] to [634272abcb].
@@ -55,21 +55,33 @@ */ typedef struct Entry { int eType; char *zFunc; char *zPath; + char *zHelp; } Entry; /* ** Maximum number of entries */ #define N_ENTRY 500 /* +** Maximum size of a help message +*/ +#define MX_HELP 10000 + +/* ** Table of entries */ Entry aEntry[N_ENTRY]; + +/* +** Current help message accumulator +*/ +char zHelp[MX_HELP]; +int nHelp; /* ** How many entries are used */ int nUsed; @@ -121,11 +133,23 @@ /* ** Scan a line for a function that implements a web page or command. */ void scan_for_func(char *zLine){ int i,j,k; + char *z; if( nUsed<=nFixed ) return; + if( strncmp(zLine, "**", 2)==0 && isspace(zLine[2]) + && strlen(zLine)<sizeof(zHelp)-nHelp-1 && nUsed>nFixed ){ + if( zLine[2]=='\n' ){ + zHelp[nHelp++] = '\n'; + }else{ + if( strncmp(&zLine[3], "Usage: ", 6)==0 ) nHelp = 0; + strcpy(&zHelp[nHelp], &zLine[3]); + nHelp += strlen(&zHelp[nHelp]); + } + return; + } for(i=0; isspace(zLine[i]); i++){} if( zLine[i]==0 ) return; if( strncmp(&zLine[i],"void",4)!=0 ){ if( zLine[i]!='*' ) goto page_skip; return; @@ -133,17 +157,28 @@ i += 4; if( !isspace(zLine[i]) ) goto page_skip; while( isspace(zLine[i]) ){ i++; } for(j=0; isalnum(zLine[i+j]) || zLine[i+j]=='_'; j++){} if( j==0 ) goto page_skip; + for(k=nHelp-1; k>=0 && isspace(zHelp[k]); k--){} + nHelp = k+1; + zHelp[nHelp] = 0; + for(k=0; k<nHelp && isspace(zHelp[k]); k++){} + if( k<nHelp ){ + z = string_dup(&zHelp[k], nHelp-k); + }else{ + z = 0; + } for(k=nFixed; k<nUsed; k++){ aEntry[k].zFunc = string_dup(&zLine[i], j); + aEntry[k].zHelp = z; } i+=j; while( isspace(zLine[i]) ){ i++; } if( zLine[i]!='(' ) goto page_skip; nFixed = nUsed; + nHelp = 0; return; page_skip: for(i=nFixed; i<nUsed; i++){ fprintf(stderr,"%s:%d: skipping page \"%s\"\n", @@ -168,10 +203,11 @@ /* ** Build the binary search table. */ void build_table(void){ int i; + int nType0; qsort(aEntry, nFixed, sizeof(aEntry[0]), e_compare); for(i=0; i<nFixed; i++){ printf("extern void %s(void);\n", aEntry[i].zFunc); } @@ -188,18 +224,49 @@ aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", aEntry[i].zFunc ); } printf("};\n"); + nType0 = i; printf( "static const NameMap aCommand[] = {\n" ); - for(; i<nFixed && aEntry[i].eType==1; i++){ + for(i=nType0; i<nFixed && aEntry[i].eType==1; i++){ printf(" { \"%s\",%*s %s },\n", aEntry[i].zPath, (int)(25-strlen(aEntry[i].zPath)), "", aEntry[i].zFunc ); + } + printf("};\n"); + for(i=nType0; i<nFixed; i++){ + char *z = aEntry[i].zHelp; + if( z && z[0] ){ + printf("static const char zHelp_%s[] = \n", aEntry[i].zFunc); + printf(" \""); + while( *z ){ + if( *z=='\n' ){ + printf("\\n\"\n \""); + }else if( *z=='"' ){ + printf("\\\""); + }else{ + putchar(*z); + } + z++; + } + printf("\";\n"); + aEntry[i].zHelp[0] = 0; + } + } + printf( + "static const char * const aCmdHelp[] = {\n" + ); + for(i=nType0; i<nFixed; i++){ + if( aEntry[i].zHelp==0 ){ + printf(" 0,\n"); + }else{ + printf(" zHelp_%s,\n", aEntry[i].zFunc); + } } printf("};\n"); } /*