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