Index: src/main.c ================================================================== --- src/main.c +++ src/main.c @@ -516,10 +516,99 @@ sqlite3_snprintf(sizeof(zCode),zCode,"error code %d",iCode); } } return zCode; } + +static void update_cmd_usage_stats(char const * zCommand){ + if(!g.localOpen || g.isHTTP) return + /* We need an opened checkout and do not want to log the 'ui' bits + forked by local ui mode. */; + db_multi_exec("CREATE TABLE IF NOT EXISTS " + "cmd_usage (name TEXT,mtime FLOAT);" + "INSERT INTO cmd_usage (name,mtime) VALUES (%Q,julianday('now'));", + zCommand); + +} + +/* +** COMMAND: usage* +** +** Usage: %fossil usage [-clear|-c] [-n|-count ###] +** +** Reports or clears information from the local checkout's cmd_usage +** table (if any). The cmd_usage table is updated each time a fossil +** CLI command succeeds (returns). The db has (name TEXT, mtime FLOAT +** (Julian Day)) fields for collecting statistics about usage. This +** information is stored in the local checkout db and is not +** synchronized. +** +** The -n|-count ### option changes the output to list the last ### +** commands used, ordered by time (most recent first). A value of 0 +** means "no limit", and lists all history for the checkout. If the +** ### value is negative, it is ignored (treated as if -n had not been +** specified). +*/ +void usage_cmd(){ + int rc; + Stmt q; + int i = 0; + int fClear = find_option("clear","c",0)!=0; + char const *zLimit = find_option("n","count",1); + int fLimit = zLimit ? atoi(zLimit) : -1; + char const * sql; + if(!db_open_local(0)){ + fossil_fatal("'usage' requires a checkout."); + } + if(fLimit>=0){ + sql = "SELECT name, strftime('%%Y-%%m-%%d %%H:%%M:%%S',mtime) " + "FROM cmd_usage ORDER BY mtime DESC"; + }else{ + sql = "SELECT name, count(*) AS n " + "FROM cmd_usage GROUP BY name " + "ORDER BY n DESC"; + } + rc = db_prepare_ignore_error(&q,sql); + if(rc){ + /* Assume missing cmd_usage table. */ + fossil_print("(An sqlite error message is normal the first time " + "this is run for a given checkout!)\n" + "No command usage history has been collected " + "for this checkout.\n"); + return; + } + if(fClear){ + db_multi_exec("DELETE FROM cmd_usage;"); + fossil_print("Usage history cleared.\n"); + db_finalize(&q); + return; + } + if(fLimit>=0){ + if(fLimit>0) fossil_print("Most recent %d CLI command(s):\n", fLimit); + else fossil_print("All CLI command history:\n"); + fossil_print("Time Command\n"); + }else{ + fossil_print("CLI command usage history for this checkout:\n"); + fossil_print("Count Command\n"); + } + while(SQLITE_ROW==db_step(&q)){ + ++i; + if(fLimit>=0){ + fossil_print("%s %s\n", db_column_text(&q, 1), + db_column_text(&q,0)); + if(i==fLimit) break; + }else{ + fossil_print("%5d %s\n", db_column_int(&q, 1), + db_column_text(&q,0)); + } + } + db_finalize(&q); + if(!i){ + fossil_print("No command usage history has been collected " + "for this checkout.\n"); + } +} /* Error logs from SQLite */ static void fossil_sqlite_log(void *notUsed, int iCode, const char *zErrmsg){ #ifdef __APPLE__ /* Disable the file alias warning on apple products because Time Machine @@ -646,10 +735,11 @@ g.argv[0], zCmdName, g.argv[0], blob_str(&couldbe), g.argv[0]); fossil_exit(1); } atexit( fossil_atexit ); aCommand[idx].xFunc(); + update_cmd_usage_stats(aCommand[idx].zName); fossil_exit(0); /*NOT_REACHED*/ return 0; }