1 #ifdef FOSSIL_ENABLE_JSON
2 /*
3 ** Copyright (c) 2013 D. Richard Hipp
4 **
5 ** This program is free software; you can redistribute it and/or
6 ** modify it under the terms of the Simplified BSD License (also
7 ** known as the "2-Clause License" or "FreeBSD License".)
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but without any warranty; without even the implied warranty of
11 ** merchantability or fitness for a particular purpose.
12 **
13 ** Author contact information:
14 ** drh@hwaci.com
15 ** http://www.hwaci.com/drh/
16 **
17 */
18
19 #include "config.h"
20 #include "json_status.h"
21
22 #if INTERFACE
23 #include "json_detail.h"
24 #endif
25
26 /*
27 Reminder to check if a column exists:
28
29 PRAGMA table_info(table_name)
30
31 and search for a row where the 'name' field matches.
32
33 That assumes, of course, that table_info()'s output format
34 is stable.
35 */
36
37 /*
38 ** Implementation of the /json/status page.
39 **
40 */
json_page_status()41 cson_value * json_page_status(){
42 Stmt q = empty_Stmt;
43 cson_object * oPay;
44 /*cson_object * files;*/
45 int vid, nErr = 0;
46 cson_object * tmpO;
47 char * zTmp;
48 i64 iMtime;
49 cson_array * aFiles;
50
51 if(!db_open_local(0)){
52 json_set_err(FSL_JSON_E_DB_NEEDS_CHECKOUT, NULL);
53 return NULL;
54 }
55 oPay = cson_new_object();
56 cson_object_set(oPay, "repository",
57 json_new_string(db_repository_filename()));
58 cson_object_set(oPay, "localRoot",
59 json_new_string(g.zLocalRoot));
60 vid = db_lget_int("checkout", 0);
61 if(!vid){
62 json_set_err( FSL_JSON_E_UNKNOWN, "Can this even happen?" );
63 return 0;
64 }
65 /* TODO: dupe show_common_info() state */
66 tmpO = cson_new_object();
67 cson_object_set(oPay, "checkout", cson_object_value(tmpO));
68
69 zTmp = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
70 cson_object_set(tmpO, "uuid", json_new_string(zTmp) );
71 free(zTmp);
72
73 cson_object_set( tmpO, "tags", json_tags_for_checkin_rid(vid, 0) );
74
75 /* FIXME: optimize the datetime/timestamp queries into 1 query. */
76 zTmp = db_text(0, "SELECT datetime(mtime) || "
77 "' UTC' FROM event WHERE objid=%d",
78 vid);
79 cson_object_set(tmpO, "datetime", json_new_string(zTmp));
80 free(zTmp);
81 iMtime = db_int64(0, "SELECT CAST(strftime('%%s',mtime) AS INTEGER) "
82 "FROM event WHERE objid=%d", vid);
83 cson_object_set(tmpO, "timestamp",
84 cson_value_new_integer((cson_int_t)iMtime));
85 #if 0
86 /* TODO: add parent artifact info */
87 tmpO = cson_new_object();
88 cson_object_set( oPay, "parent", cson_object_value(tmpO) );
89 cson_object_set( tmpO, "uuid", TODO );
90 cson_object_set( tmpO, "timestamp", TODO );
91 #endif
92
93 /* Now get the list of non-pristine files... */
94 aFiles = cson_new_array();
95 cson_object_set( oPay, "files", cson_array_value( aFiles ) );
96
97 db_prepare(&q,
98 "SELECT pathname, deleted, chnged, rid, coalesce(origname!=pathname,0)"
99 " FROM vfile "
100 " WHERE is_selected(id)"
101 " AND (chnged OR deleted OR rid=0 OR pathname!=origname) ORDER BY 1"
102 );
103 while( db_step(&q)==SQLITE_ROW ){
104 const char *zPathname = db_column_text(&q,0);
105 int isDeleted = db_column_int(&q, 1);
106 int isChnged = db_column_int(&q,2);
107 int isNew = db_column_int(&q,3)==0;
108 int isRenamed = db_column_int(&q,4);
109 cson_object * oFile;
110 char const * zStatus = "???";
111 char * zFullName = mprintf("%s%s", g.zLocalRoot, zPathname);
112 if( isDeleted ){
113 zStatus = "deleted";
114 }else if( isNew ){
115 zStatus = "new" /* maintenance reminder: MUST come
116 BEFORE the isChnged checks. */;
117 }else if( isRenamed ){
118 zStatus = "renamed";
119 }else if( !file_isfile_or_link(zFullName) ){
120 if( file_access(zFullName, F_OK)==0 ){
121 zStatus = "notAFile";
122 ++nErr;
123 }else{
124 zStatus = "missing";
125 ++nErr;
126 }
127 }else if( 2==isChnged ){
128 zStatus = "updatedByMerge";
129 }else if( 3==isChnged ){
130 zStatus = "addedByMerge";
131 }else if( 4==isChnged ){
132 zStatus = "updatedByIntegrate";
133 }else if( 5==isChnged ){
134 zStatus = "addedByIntegrate";
135 }else if( 1==isChnged ){
136 if( file_contains_merge_marker(zFullName) ){
137 zStatus = "conflict";
138 }else{
139 zStatus = "edited";
140 }
141 }
142
143 oFile = cson_new_object();
144 cson_array_append( aFiles, cson_object_value(oFile) );
145 /* optimization potential: move these keys into cson_strings
146 to take advantage of refcounting. */
147 cson_object_set( oFile, "name", json_new_string( zPathname ) );
148 cson_object_set( oFile, "status", json_new_string( zStatus ) );
149
150 free(zFullName);
151 }
152 cson_object_set( oPay, "errorCount", json_new_int( nErr ) );
153 db_finalize(&q);
154
155 #if 0
156 /* TODO: add "merged with" status. First need (A) to decide on a
157 structure and (B) to set up some tests for the multi-merge
158 case.*/
159 db_prepare(&q, "SELECT mhash, id FROM vmerge WHERE id<=0");
160 while( db_step(&q)==SQLITE_ROW ){
161 const char *zLabel = "MERGED_WITH";
162 switch( db_column_int(&q, 1) ){
163 case -1: zLabel = "CHERRYPICK "; break;
164 case -2: zLabel = "BACKOUT "; break;
165 case -4: zLabel = "INTEGRATE "; break;
166 }
167 blob_append(report, zPrefix, nPrefix);
168 blob_appendf(report, "%s %s\n", zLabel, db_column_text(&q, 0));
169 }
170 db_finalize(&q);
171 if( nErr ){
172 fossil_fatal("aborting due to prior errors");
173 }
174 #endif
175 return cson_object_value( oPay );
176 }
177
178 #endif /* FOSSIL_ENABLE_JSON */
179