Fossil SCM

Re-do previous checkin - i had been editing the generated bld/manifest_.c because of PEBKAC caused by following a compilation error into that file.

stephan 2025-03-24 14:18 artifact-to-json
Commit 069995d7eaf52c67b3b73cd176a30fc048940b5e039c0318e3d082bb7736f316
1 file changed +151 -15
+151 -15
--- src/manifest.c
+++ src/manifest.c
@@ -2911,37 +2911,173 @@
29112911
if( g.argc!=3 ) usage("RECORDID");
29122912
rid = name_to_rid(g.argv[2]);
29132913
content_get(rid, &content);
29142914
manifest_crosslink(rid, &content, MC_NONE);
29152915
}
2916
+
2917
+/*
2918
+** For a given CATYPE_... value, returns a human-friendly name, or
2919
+** NULL if typeId is unknown or is CFTYPE_ANY.
2920
+*/
2921
+const char * artifact_type_to_name(int typeId){
2922
+ switch(typeId){
2923
+ case CFTYPE_MANIFEST: return "checkin";
2924
+ case CFTYPE_CLUSTER: return "cluster";
2925
+ case CFTYPE_CONTROL: return "control";
2926
+ case CFTYPE_WIKI: return "wiki";
2927
+ case CFTYPE_TICKET: return "ticket";
2928
+ case CFTYPE_ATTACHMENT: return "attachment";
2929
+ case CFTYPE_EVENT: return "event";
2930
+ case CFTYPE_FORUM: return "forumpost";
2931
+ }
2932
+ return NULL;
2933
+}
29162934
29172935
/*
29182936
** Creates a JSON representation of p, appending it to pOut.
2937
+**
2938
+** Pedantic note: this routine traverses p->aFile directly, rather than
2939
+** using manifest_file_next(), so that delta manifests are rendered as-is
2940
+** instead of having their derived files. If that policy is ever changed,
2941
+** p will need to be non-const.
29192942
*/
2920
-void artifact_to_json(Manifest *p, Blob *pOut){
2921
- char * zTmp;
2922
- blob_append_literal(pOut, "{");
2923
- blob_appendf(pOut, "\"rid\": %d", p->rid);
2924
- zTmp = rid_to_uuid(p->rid);
2925
- blob_appendf(pOut, ", \"uuid\": %!j", zTmp);
2926
- fossil_free(zTmp);
2927
-#define CARD_FMT(LETTER, FMT, VAL) \
2928
- blob_appendf(pOut, ",\"" #LETTER "\": " #FMT, VAL)
2943
+void artifact_to_json(Manifest const *p, Blob *b){
2944
+ int i;
2945
+ char *zUuid;
2946
+
2947
+ blob_append_literal(b, "{");
2948
+ blob_appendf(b, "\"rid\": %d", p->rid);
2949
+ zUuid = rid_to_uuid(p->rid);
2950
+ blob_appendf(b, ", \"uuid\": %!j", zUuid);
2951
+ blob_appendf(b, ", \"type\": %!j", artifact_type_to_name(p->type));
2952
+#define ISA(TYPE) if( p->type==TYPE )
2953
+#define CARD_LETTER(LETTER) \
2954
+ blob_append_literal(b, ",\"" #LETTER "\": ")
29292955
#define CARD_STR(LETTER, VAL) \
2930
- assert( VAL ); CARD_FMT(LETTER, %!j, VAL)
2956
+ assert( VAL ); CARD_LETTER(LETTER); blob_appendf(b, "%!j", VAL)
29312957
#define CARD_STR2(LETTER, VAL) \
2932
- if( VAL ) { CARD_FMT(LETTER, %!j, VAL); }
2958
+ if( VAL ) { CARD_STR(LETTER, VAL); } (void)0
2959
+#define STR_OR_NULL(VAL) \
2960
+ if( VAL ) blob_appendf(b, "%!j", VAL); \
2961
+ else blob_append(b, "null", 4)
2962
+#define KVP_STR(ADDCOMMA, KEY,VAL) \
2963
+ if(ADDCOMMA) blob_append_char(b, ','); \
2964
+ blob_appendf(b, "%!j: ", #KEY); \
2965
+ STR_OR_NULL(VAL)
29332966
2967
+ /* Noting that only 1 (at most) of the A-card pieces will be non-NULL... */
2968
+ ISA( CFTYPE_ATTACHMENT ){
2969
+ CARD_LETTER(A);
2970
+ blob_append_char(b, '{');
2971
+ KVP_STR(0, filename, p->zAttachName);
2972
+ KVP_STR(1, target, p->zAttachTarget);
2973
+ KVP_STR(1, source, p->zAttachSrc);
2974
+ blob_append_char(b, '}');
2975
+ }
29342976
CARD_STR2(B, p->zBaseline);
29352977
CARD_STR2(C, p->zComment);
2936
- CARD_FMT(D, %f, p->rDate);
2937
- CARD_STR2(W, p->zWiki);
2978
+ CARD_LETTER(D); blob_appendf(b, "%f", p->rDate);
2979
+ ISA( CFTYPE_EVENT ){
2980
+ blob_appendf(b, ", \"E\": {\"time\": %f, \"id\": %!j}",
2981
+ p->rEventDate, p->zEventId);
2982
+ }
2983
+ ISA( CFTYPE_MANIFEST ){
2984
+ CARD_LETTER(F);
2985
+ blob_append_char(b, '[');
2986
+ for( i = 0; i < p->nFile; ++i ){
2987
+ ManifestFile const * const pF = &p->aFile[i];
2988
+ if( i>0 ) blob_append_char(b, ',');
2989
+ blob_append_char(b, '{');
2990
+ KVP_STR(0, name, pF->zName);
2991
+ KVP_STR(1, uuid, pF->zUuid);
2992
+ KVP_STR(1, perm, pF->zPerm);
2993
+ KVP_STR(1, oldName, pF->zPrior);
2994
+ blob_append_char(b, '}');
2995
+ }
2996
+ blob_append_char(b, ']');
2997
+ }
2998
+ CARD_STR2(G, p->zThreadRoot);
2999
+ CARD_STR2(H, p->zThreadTitle);
3000
+ CARD_STR2(I, p->zInReplyTo);
3001
+ if( p->nField ){
3002
+ CARD_LETTER(J);
3003
+ blob_append_char(b, '[');
3004
+ for( i = 0; i < p->nField; ++i ){
3005
+ if( i>0 ) blob_append_char(b, ',');
3006
+ blob_append_char(b, '{');
3007
+ KVP_STR(0, name, p->aField[i].zName);
3008
+ KVP_STR(1, value, p->aField[i].zValue);
3009
+ blob_append_char(b, '}');
3010
+ }
3011
+ blob_append_char(b, ']');
3012
+ }
3013
+ CARD_STR2(K, p->zTicketUuid);
3014
+ CARD_STR2(L, p->zWikiTitle);
3015
+ ISA( CFTYPE_CLUSTER && p->nCChild>0 ){
3016
+ CARD_LETTER(M);
3017
+ blob_append_char(b, '[');
3018
+ for( int i = 0; i < p->nCChild; ++i ){
3019
+ if( i>0 ) blob_append_char(b, ',');
3020
+ blob_appendf(b, "%!j", p->azCChild[i]);
3021
+ }
3022
+ blob_append_char(b, ']');
3023
+ }
3024
+ CARD_STR2(N, p->zMimetype);
3025
+ if( p->nParent ){
3026
+ CARD_LETTER(P);
3027
+ blob_append_char(b, '[');
3028
+ for( i = 0; i < p->nParent; ++i ){
3029
+ if( i>0 ) blob_append_char(b, ',');
3030
+ blob_appendf(b, "%!j", p->azParent[i]);
3031
+ }
3032
+ blob_append_char(b, ']');
3033
+ }
3034
+ if( p->nCherrypick ){
3035
+ CARD_LETTER(Q);
3036
+ blob_append_char(b, '[');
3037
+ for( i = 0; i < p->nCherrypick; ++i ){
3038
+ if( i>0 ) blob_append_char(b, ',');
3039
+ blob_append_char(b, '{');
3040
+ blob_appendf(b, "\"type\": \"%c\"", p->aCherrypick[i].zCPTarget[0]);
3041
+ KVP_STR(1, target, &p->aCherrypick[i].zCPTarget[1]);
3042
+ KVP_STR(1, base, p->aCherrypick[i].zCPBase);
3043
+ blob_append_char(b, '}');
3044
+ }
3045
+ blob_append_char(b, ']');
3046
+ }
29383047
CARD_STR2(R, p->zRepoCksum);
2939
- blob_append_literal(pOut, "}");
3048
+ if( p->nTag ){
3049
+ CARD_LETTER(T);
3050
+ blob_append_char(b, '[');
3051
+ for( int i = 0; i < p->nTag; ++i ){
3052
+ const char *zName = p->aTag[i].zName;
3053
+ if( i>0 ) blob_append_char(b, ',');
3054
+ blob_append_char(b, '{');
3055
+ blob_appendf(b, "\"type\": \"%c\"", *zName);
3056
+ ++zName;
3057
+ KVP_STR(1, name, zName);
3058
+ KVP_STR(1, target, p->aTag[i].zUuid ? p->aTag[i].zUuid : "*")
3059
+ /* We could arguably resolve this to null. Per /chat
3060
+ discussion we don't want to resolve it to zUuid because
3061
+ that would effectively add information to the rendered
3062
+ manifest. */;
3063
+ KVP_STR(1, value, p->aTag[i].zValue);
3064
+ blob_append_char(b, '}');
3065
+ }
3066
+ blob_append_char(b, ']');
3067
+ }
3068
+ CARD_STR2(U, p->zUser);
3069
+ CARD_STR2(W, p->zWiki);
3070
+ fossil_free(zUuid);
3071
+ blob_append_literal(b, "}");
3072
+#undef CARD_FMT
3073
+#undef CARD_LETTER
29403074
#undef CARD_STR
29413075
#undef CARD_STR2
2942
-#undef CARD_FMT
3076
+#undef ISA
3077
+#undef KVP_STR
3078
+#undef STR_OR_NULL
29433079
}
29443080
29453081
/*
29463082
** Convenience wrapper around artifact_to_json() which accepts any
29473083
** artifact name which is legal for symbolic_name_to_rid(). On success
29483084
--- src/manifest.c
+++ src/manifest.c
@@ -2911,37 +2911,173 @@
2911 if( g.argc!=3 ) usage("RECORDID");
2912 rid = name_to_rid(g.argv[2]);
2913 content_get(rid, &content);
2914 manifest_crosslink(rid, &content, MC_NONE);
2915 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2916
2917 /*
2918 ** Creates a JSON representation of p, appending it to pOut.
 
 
 
 
 
2919 */
2920 void artifact_to_json(Manifest *p, Blob *pOut){
2921 char * zTmp;
2922 blob_append_literal(pOut, "{");
2923 blob_appendf(pOut, "\"rid\": %d", p->rid);
2924 zTmp = rid_to_uuid(p->rid);
2925 blob_appendf(pOut, ", \"uuid\": %!j", zTmp);
2926 fossil_free(zTmp);
2927 #define CARD_FMT(LETTER, FMT, VAL) \
2928 blob_appendf(pOut, ",\"" #LETTER "\": " #FMT, VAL)
 
 
 
2929 #define CARD_STR(LETTER, VAL) \
2930 assert( VAL ); CARD_FMT(LETTER, %!j, VAL)
2931 #define CARD_STR2(LETTER, VAL) \
2932 if( VAL ) { CARD_FMT(LETTER, %!j, VAL); }
 
 
 
 
 
 
 
2933
 
 
 
 
 
 
 
 
 
2934 CARD_STR2(B, p->zBaseline);
2935 CARD_STR2(C, p->zComment);
2936 CARD_FMT(D, %f, p->rDate);
2937 CARD_STR2(W, p->zWiki);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2938 CARD_STR2(R, p->zRepoCksum);
2939 blob_append_literal(pOut, "}");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2940 #undef CARD_STR
2941 #undef CARD_STR2
2942 #undef CARD_FMT
 
 
2943 }
2944
2945 /*
2946 ** Convenience wrapper around artifact_to_json() which accepts any
2947 ** artifact name which is legal for symbolic_name_to_rid(). On success
2948
--- src/manifest.c
+++ src/manifest.c
@@ -2911,37 +2911,173 @@
2911 if( g.argc!=3 ) usage("RECORDID");
2912 rid = name_to_rid(g.argv[2]);
2913 content_get(rid, &content);
2914 manifest_crosslink(rid, &content, MC_NONE);
2915 }
2916
2917 /*
2918 ** For a given CATYPE_... value, returns a human-friendly name, or
2919 ** NULL if typeId is unknown or is CFTYPE_ANY.
2920 */
2921 const char * artifact_type_to_name(int typeId){
2922 switch(typeId){
2923 case CFTYPE_MANIFEST: return "checkin";
2924 case CFTYPE_CLUSTER: return "cluster";
2925 case CFTYPE_CONTROL: return "control";
2926 case CFTYPE_WIKI: return "wiki";
2927 case CFTYPE_TICKET: return "ticket";
2928 case CFTYPE_ATTACHMENT: return "attachment";
2929 case CFTYPE_EVENT: return "event";
2930 case CFTYPE_FORUM: return "forumpost";
2931 }
2932 return NULL;
2933 }
2934
2935 /*
2936 ** Creates a JSON representation of p, appending it to pOut.
2937 **
2938 ** Pedantic note: this routine traverses p->aFile directly, rather than
2939 ** using manifest_file_next(), so that delta manifests are rendered as-is
2940 ** instead of having their derived files. If that policy is ever changed,
2941 ** p will need to be non-const.
2942 */
2943 void artifact_to_json(Manifest const *p, Blob *b){
2944 int i;
2945 char *zUuid;
2946
2947 blob_append_literal(b, "{");
2948 blob_appendf(b, "\"rid\": %d", p->rid);
2949 zUuid = rid_to_uuid(p->rid);
2950 blob_appendf(b, ", \"uuid\": %!j", zUuid);
2951 blob_appendf(b, ", \"type\": %!j", artifact_type_to_name(p->type));
2952 #define ISA(TYPE) if( p->type==TYPE )
2953 #define CARD_LETTER(LETTER) \
2954 blob_append_literal(b, ",\"" #LETTER "\": ")
2955 #define CARD_STR(LETTER, VAL) \
2956 assert( VAL ); CARD_LETTER(LETTER); blob_appendf(b, "%!j", VAL)
2957 #define CARD_STR2(LETTER, VAL) \
2958 if( VAL ) { CARD_STR(LETTER, VAL); } (void)0
2959 #define STR_OR_NULL(VAL) \
2960 if( VAL ) blob_appendf(b, "%!j", VAL); \
2961 else blob_append(b, "null", 4)
2962 #define KVP_STR(ADDCOMMA, KEY,VAL) \
2963 if(ADDCOMMA) blob_append_char(b, ','); \
2964 blob_appendf(b, "%!j: ", #KEY); \
2965 STR_OR_NULL(VAL)
2966
2967 /* Noting that only 1 (at most) of the A-card pieces will be non-NULL... */
2968 ISA( CFTYPE_ATTACHMENT ){
2969 CARD_LETTER(A);
2970 blob_append_char(b, '{');
2971 KVP_STR(0, filename, p->zAttachName);
2972 KVP_STR(1, target, p->zAttachTarget);
2973 KVP_STR(1, source, p->zAttachSrc);
2974 blob_append_char(b, '}');
2975 }
2976 CARD_STR2(B, p->zBaseline);
2977 CARD_STR2(C, p->zComment);
2978 CARD_LETTER(D); blob_appendf(b, "%f", p->rDate);
2979 ISA( CFTYPE_EVENT ){
2980 blob_appendf(b, ", \"E\": {\"time\": %f, \"id\": %!j}",
2981 p->rEventDate, p->zEventId);
2982 }
2983 ISA( CFTYPE_MANIFEST ){
2984 CARD_LETTER(F);
2985 blob_append_char(b, '[');
2986 for( i = 0; i < p->nFile; ++i ){
2987 ManifestFile const * const pF = &p->aFile[i];
2988 if( i>0 ) blob_append_char(b, ',');
2989 blob_append_char(b, '{');
2990 KVP_STR(0, name, pF->zName);
2991 KVP_STR(1, uuid, pF->zUuid);
2992 KVP_STR(1, perm, pF->zPerm);
2993 KVP_STR(1, oldName, pF->zPrior);
2994 blob_append_char(b, '}');
2995 }
2996 blob_append_char(b, ']');
2997 }
2998 CARD_STR2(G, p->zThreadRoot);
2999 CARD_STR2(H, p->zThreadTitle);
3000 CARD_STR2(I, p->zInReplyTo);
3001 if( p->nField ){
3002 CARD_LETTER(J);
3003 blob_append_char(b, '[');
3004 for( i = 0; i < p->nField; ++i ){
3005 if( i>0 ) blob_append_char(b, ',');
3006 blob_append_char(b, '{');
3007 KVP_STR(0, name, p->aField[i].zName);
3008 KVP_STR(1, value, p->aField[i].zValue);
3009 blob_append_char(b, '}');
3010 }
3011 blob_append_char(b, ']');
3012 }
3013 CARD_STR2(K, p->zTicketUuid);
3014 CARD_STR2(L, p->zWikiTitle);
3015 ISA( CFTYPE_CLUSTER && p->nCChild>0 ){
3016 CARD_LETTER(M);
3017 blob_append_char(b, '[');
3018 for( int i = 0; i < p->nCChild; ++i ){
3019 if( i>0 ) blob_append_char(b, ',');
3020 blob_appendf(b, "%!j", p->azCChild[i]);
3021 }
3022 blob_append_char(b, ']');
3023 }
3024 CARD_STR2(N, p->zMimetype);
3025 if( p->nParent ){
3026 CARD_LETTER(P);
3027 blob_append_char(b, '[');
3028 for( i = 0; i < p->nParent; ++i ){
3029 if( i>0 ) blob_append_char(b, ',');
3030 blob_appendf(b, "%!j", p->azParent[i]);
3031 }
3032 blob_append_char(b, ']');
3033 }
3034 if( p->nCherrypick ){
3035 CARD_LETTER(Q);
3036 blob_append_char(b, '[');
3037 for( i = 0; i < p->nCherrypick; ++i ){
3038 if( i>0 ) blob_append_char(b, ',');
3039 blob_append_char(b, '{');
3040 blob_appendf(b, "\"type\": \"%c\"", p->aCherrypick[i].zCPTarget[0]);
3041 KVP_STR(1, target, &p->aCherrypick[i].zCPTarget[1]);
3042 KVP_STR(1, base, p->aCherrypick[i].zCPBase);
3043 blob_append_char(b, '}');
3044 }
3045 blob_append_char(b, ']');
3046 }
3047 CARD_STR2(R, p->zRepoCksum);
3048 if( p->nTag ){
3049 CARD_LETTER(T);
3050 blob_append_char(b, '[');
3051 for( int i = 0; i < p->nTag; ++i ){
3052 const char *zName = p->aTag[i].zName;
3053 if( i>0 ) blob_append_char(b, ',');
3054 blob_append_char(b, '{');
3055 blob_appendf(b, "\"type\": \"%c\"", *zName);
3056 ++zName;
3057 KVP_STR(1, name, zName);
3058 KVP_STR(1, target, p->aTag[i].zUuid ? p->aTag[i].zUuid : "*")
3059 /* We could arguably resolve this to null. Per /chat
3060 discussion we don't want to resolve it to zUuid because
3061 that would effectively add information to the rendered
3062 manifest. */;
3063 KVP_STR(1, value, p->aTag[i].zValue);
3064 blob_append_char(b, '}');
3065 }
3066 blob_append_char(b, ']');
3067 }
3068 CARD_STR2(U, p->zUser);
3069 CARD_STR2(W, p->zWiki);
3070 fossil_free(zUuid);
3071 blob_append_literal(b, "}");
3072 #undef CARD_FMT
3073 #undef CARD_LETTER
3074 #undef CARD_STR
3075 #undef CARD_STR2
3076 #undef ISA
3077 #undef KVP_STR
3078 #undef STR_OR_NULL
3079 }
3080
3081 /*
3082 ** Convenience wrapper around artifact_to_json() which accepts any
3083 ** artifact name which is legal for symbolic_name_to_rid(). On success
3084

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button