Fossil SCM
Initial infrastructure for "web commit".
Commit
cb4d48ac058b9012cc339dd67f67723b7f5909cb3a5646918b6d9d20266a9bb6
Parent
483ac3db837246c…
1 file changed
+243
+243
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -2672,5 +2672,248 @@ | ||
| 2672 | 2672 | } |
| 2673 | 2673 | if( count_nonbranch_children(vid)>1 ){ |
| 2674 | 2674 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 2675 | 2675 | } |
| 2676 | 2676 | } |
| 2677 | + | |
| 2678 | +#if INTERFACE | |
| 2679 | +/* | |
| 2680 | +** State for the "web-checkin" infrastructure, which enables the | |
| 2681 | +** ability to commit changes to a single file via an HTTP request. | |
| 2682 | + */ | |
| 2683 | +struct CheckinWebInfo { | |
| 2684 | + Blob comment; /* Check-in comment text */ | |
| 2685 | + char *zMimetype; /* Mimetype of check-in command. May be NULL */ | |
| 2686 | + Manifest * pParent; /* parent checkin */ | |
| 2687 | + const char *zUser; /* User name */ | |
| 2688 | + char *zFilename; /* Name of single file to commit. */ | |
| 2689 | + Blob fileContent; /* Content of the modified file. */ | |
| 2690 | + Blob fileHash; /* Hash of this->fileContent */ | |
| 2691 | +}; | |
| 2692 | +#endif /* INTERFACE */ | |
| 2693 | + | |
| 2694 | +static void CheckinWebInfo_init( CheckinWebInfo * p ){ | |
| 2695 | + memset(p, 0, sizeof(struct CheckinWebInfo)); | |
| 2696 | + p->comment = p->fileContent = p->fileHash = empty_blob; | |
| 2697 | +} | |
| 2698 | + | |
| 2699 | +static void CheckinWebInfo_cleanup( CheckinWebInfo * p ){ | |
| 2700 | + blob_reset(&p->comment); | |
| 2701 | + blob_reset(&p->fileContent); | |
| 2702 | + blob_reset(&p->fileHash); | |
| 2703 | + if(p->pParent){ | |
| 2704 | + manifest_destroy(p->pParent); | |
| 2705 | + } | |
| 2706 | + fossil_free(p->zFilename); | |
| 2707 | + fossil_free(p->zMimetype); | |
| 2708 | + CheckinWebInfo_init(p); | |
| 2709 | +} | |
| 2710 | + | |
| 2711 | +/* | |
| 2712 | +** Creates a manifest file, written to pOut, from the state in the | |
| 2713 | +** fully-populated pCI argument. On error, returns non-0 and, if | |
| 2714 | +** pErr is not NULL, writes an error message there. | |
| 2715 | +*/ | |
| 2716 | +static int create_manifest_web( Blob * pOut, CheckinWebInfo * pCI, | |
| 2717 | + Blob * pErr){ | |
| 2718 | + Blob zCard = empty_blob; | |
| 2719 | + ManifestFile *zFile; | |
| 2720 | + int cmp = -99; | |
| 2721 | + const char *zPerm = ""; | |
| 2722 | + const char *zFilename = 0; | |
| 2723 | + const char *zUuid = 0; | |
| 2724 | + int (*fncmp)(char const *, char const *) = | |
| 2725 | + filenames_are_case_sensitive() | |
| 2726 | + ? fossil_strcmp | |
| 2727 | + : fossil_stricmp; | |
| 2728 | + | |
| 2729 | +#define mf_err(MSG) if(pErr) blob_append(pErr,MSG,-1); return 1 | |
| 2730 | + /* Potential TODOs include... | |
| 2731 | + ** - Create a delta manifest, if possible, rather than a baseline. | |
| 2732 | + ** - Enable adding of new files? It's implemented by disabled until | |
| 2733 | + ** we at least ensure that pCI->zFilename is a path-relative | |
| 2734 | + ** filename. | |
| 2735 | + ** - Maybe add support for tags. Those can be edited via /info page. | |
| 2736 | + ** - Check for a commit to a closed leaf and re-open it. | |
| 2737 | + */ | |
| 2738 | + blob_zero(pOut); | |
| 2739 | + if(blob_size(&pCI->comment)!=0){ | |
| 2740 | + blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment)); | |
| 2741 | + }else{ | |
| 2742 | + blob_append(pOut, "C (no\\scomment)\n", 16); | |
| 2743 | + } | |
| 2744 | + blob_appendf(pOut, "D %z\n", date_in_standard_format("now")); | |
| 2745 | + | |
| 2746 | + manifest_file_rewind(pCI->pParent); | |
| 2747 | + while((zFile = manifest_file_next(pCI->pParent, 0))){ | |
| 2748 | + cmp = fncmp(zFile->zName, pCI->zFilename); | |
| 2749 | + if(cmp<0){ | |
| 2750 | + blob_appendf(pOut, "F %F %s%s\n", zFile->zName, zFile->zUuid, | |
| 2751 | + zFile->zPerm); | |
| 2752 | + }else{ | |
| 2753 | + break; | |
| 2754 | + } | |
| 2755 | + } | |
| 2756 | + if(cmp==0){ /* Match */ | |
| 2757 | + const int perm = manifest_file_mperm(zFile); | |
| 2758 | + if(PERM_LNK==perm){ | |
| 2759 | + mf_err("Cannot commit symlinks with this approach."); | |
| 2760 | + } | |
| 2761 | + zPerm = PERM_EXE==perm ? " x" : ""; | |
| 2762 | + zFilename = zFile->zName | |
| 2763 | + /* use original name in case of case difference */; | |
| 2764 | + zUuid = blob_str(&pCI->fileHash); | |
| 2765 | + }else{ | |
| 2766 | + /* This is a new file. */ | |
| 2767 | + zFilename = pCI->zFilename; | |
| 2768 | + zPerm = ""; | |
| 2769 | + zUuid = blob_str(&pCI->fileHash); | |
| 2770 | + if(cmp>0){ | |
| 2771 | + assert(zFile!=0); | |
| 2772 | + assert(pCI->pParent->iFile>0); | |
| 2773 | + --pCI->pParent->iFile | |
| 2774 | + /* so that the next step picks up that entry again */; | |
| 2775 | + } | |
| 2776 | + } | |
| 2777 | + assert(zFilename); | |
| 2778 | + assert(zUuid); | |
| 2779 | + assert(zPerm); | |
| 2780 | + blob_appendf(pOut, "F %F %s%s\n", zFilename, zUuid, zPerm); | |
| 2781 | + while((zFile = manifest_file_next(pCI->pParent, 0))){ | |
| 2782 | + cmp = fncmp(zFile->zName, pCI->zFilename); | |
| 2783 | + assert(cmp>0); | |
| 2784 | + if(cmp<=0){ | |
| 2785 | + mf_err("Mis-ordering of F-cards."); | |
| 2786 | + } | |
| 2787 | + blob_appendf(pOut, "F %F %s%s%s\n", | |
| 2788 | + zFile->zName, zFile->zUuid, | |
| 2789 | + (zFile->zPerm && *zFile->zPerm) ? " " : "", | |
| 2790 | + (zFile->zPerm && *zFile->zPerm) ? zFile->zPerm : ""); | |
| 2791 | + } | |
| 2792 | + | |
| 2793 | + if(pCI->zMimetype){ | |
| 2794 | + blob_appendf(pOut, "N %F\n", pCI->zMimetype); | |
| 2795 | + } | |
| 2796 | + | |
| 2797 | + blob_appendf(pOut, "P %z\n", | |
| 2798 | + db_text(0,"SELECT uuid FROM blob WHERE rid=%d", | |
| 2799 | + pCI->pParent->rid)); | |
| 2800 | + blob_appendf(pOut, "U %F\n", pCI->zUser); | |
| 2801 | + md5sum_blob(pOut, &zCard); | |
| 2802 | + blob_appendf(pOut, "Z %b\n", &zCard); | |
| 2803 | + blob_reset(&zCard); | |
| 2804 | + return 0; | |
| 2805 | +#undef mf_err | |
| 2806 | +} | |
| 2807 | + | |
| 2808 | +/* | |
| 2809 | +** EXPERIMENTAL! A so-called "web checkin" is a slimmed-down form of | |
| 2810 | +** the checkin command which accepts only a single file and is | |
| 2811 | +** intended to accept edits to a file via the web interface. | |
| 2812 | +** | |
| 2813 | +** This routine uses the state from the given fully-populated pCI | |
| 2814 | +** argument to add pCI->fileContent to the database, and create and | |
| 2815 | +** save a manifest for that change. | |
| 2816 | +** | |
| 2817 | +** Fails fatally on error. If pRid is not NULL, the RID of the | |
| 2818 | +** resulting manifest is written to *pRid. If bDryRun is true, | |
| 2819 | +** it rolls back its transaction, else it commits as usual. | |
| 2820 | +** | |
| 2821 | +*/ | |
| 2822 | +void checkin_web( CheckinWebInfo * pCI, int *pRid, int bDryRun ){ | |
| 2823 | + Blob mf = empty_blob; | |
| 2824 | + Blob err = empty_blob; | |
| 2825 | + int rid = 0, frid = 0; | |
| 2826 | + const int isPrivate = content_is_private(pCI->pParent->rid); | |
| 2827 | + ManifestFile * zFile; | |
| 2828 | + | |
| 2829 | + db_begin_transaction(); | |
| 2830 | + if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){ | |
| 2831 | + fossil_fatal("no such user: %s", pCI->zUser); | |
| 2832 | + } | |
| 2833 | + manifest_file_rewind(pCI->pParent); | |
| 2834 | + zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); | |
| 2835 | + if(!zFile){ | |
| 2836 | + fossil_fatal("File [%s] not found in manifest. " | |
| 2837 | + "Adding new files is currently not allowed.", | |
| 2838 | + pCI->zFilename); | |
| 2839 | + } | |
| 2840 | + if(create_manifest_web(&mf, pCI, &err)!=0){ | |
| 2841 | + fossil_fatal("create_manifest_web() failed: %B", &err); | |
| 2842 | + } | |
| 2843 | + frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash), | |
| 2844 | + 0, 0, isPrivate); | |
| 2845 | + manifest_file_rewind(pCI->pParent); | |
| 2846 | + zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); | |
| 2847 | + if(zFile!=0){ | |
| 2848 | + int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q", | |
| 2849 | + zFile->zUuid); | |
| 2850 | + assert(prevFRid>0); | |
| 2851 | + content_deltify(frid, &prevFRid, 1, 0); | |
| 2852 | + } | |
| 2853 | + rid = content_put_ex(&mf, 0, 0, 0, isPrivate); | |
| 2854 | + if(pRid!=0){ | |
| 2855 | + *pRid = rid; | |
| 2856 | + } | |
| 2857 | + fossil_print("Manifest:\n%b", &mf); | |
| 2858 | + manifest_crosslink(rid, &mf, 0); | |
| 2859 | + if(bDryRun){ | |
| 2860 | + fossil_print("Rolling back transaction.\n"); | |
| 2861 | + } | |
| 2862 | + db_end_transaction(bDryRun ? 1 : 0); | |
| 2863 | + blob_reset(&mf); | |
| 2864 | +} | |
| 2865 | + | |
| 2866 | +/* | |
| 2867 | +** COMMAND: test-ci-web | |
| 2868 | +** | |
| 2869 | +** This is an on-going experiment, subject to change or removal at | |
| 2870 | +** any time. | |
| 2871 | +** | |
| 2872 | +** Usage: %fossil ?OPTIONS? FILENAME | |
| 2873 | +** | |
| 2874 | +** where FILENAME is a repo-relative name as it would appear in the | |
| 2875 | +** vfile table. | |
| 2876 | +*/ | |
| 2877 | +void test_ci_one_cmd(){ | |
| 2878 | + CheckinWebInfo cinf; | |
| 2879 | + int parentVid = 0, newRid = 0; | |
| 2880 | + const char * zFilename; | |
| 2881 | + const char * zComment; | |
| 2882 | + const char * zAsFilename; | |
| 2883 | + int wetRunFlag = 0; | |
| 2884 | + | |
| 2885 | + if(g.argc<3){ | |
| 2886 | + usage("INFILE"); | |
| 2887 | + } | |
| 2888 | + db_find_and_open_repository(0, 0); | |
| 2889 | + wetRunFlag = find_option("wet-run",0,0)!=0; | |
| 2890 | + zComment = find_option("comment","m",1); | |
| 2891 | + zAsFilename = find_option("as",0,1); | |
| 2892 | + verify_all_options(); | |
| 2893 | + user_select(); | |
| 2894 | + | |
| 2895 | + zFilename = g.argv[2]; | |
| 2896 | + CheckinWebInfo_init(&cinf); | |
| 2897 | + blob_append(&cinf.comment, | |
| 2898 | + zComment ? zComment : "This is a test comment.", | |
| 2899 | + -1); | |
| 2900 | + cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename); | |
| 2901 | + cinf.zUser = login_name(); | |
| 2902 | + | |
| 2903 | + cinf.pParent = manifest_get_by_name("trunk", &parentVid); | |
| 2904 | + assert(parentVid>0); | |
| 2905 | + assert(cinf.pParent!=0); | |
| 2906 | + blob_read_from_file(&cinf.fileContent, zFilename, | |
| 2907 | + ExtFILE/*may want to reconsider*/); | |
| 2908 | + sha3sum_init(256); | |
| 2909 | + sha3sum_step_blob(&cinf.fileContent); | |
| 2910 | + sha3sum_finish(&cinf.fileHash); | |
| 2911 | + checkin_web(&cinf, &newRid, wetRunFlag ? 0 : 1); | |
| 2912 | + CheckinWebInfo_cleanup(&cinf); | |
| 2913 | + if(wetRunFlag!=0 && newRid!=0 && g.localOpen!=0){ | |
| 2914 | + fossil_warning("The checkout state is now out of sync " | |
| 2915 | + "with regards to this commit. It needs to be " | |
| 2916 | + "'update'd or 'close'd and re-'open'ed."); | |
| 2917 | + /* vfile_check_signature(newRid,0); does not do the trick */ | |
| 2918 | + } | |
| 2919 | +} | |
| 2677 | 2920 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2672,5 +2672,248 @@ | |
| 2672 | } |
| 2673 | if( count_nonbranch_children(vid)>1 ){ |
| 2674 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 2675 | } |
| 2676 | } |
| 2677 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -2672,5 +2672,248 @@ | |
| 2672 | } |
| 2673 | if( count_nonbranch_children(vid)>1 ){ |
| 2674 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 2675 | } |
| 2676 | } |
| 2677 | |
| 2678 | #if INTERFACE |
| 2679 | /* |
| 2680 | ** State for the "web-checkin" infrastructure, which enables the |
| 2681 | ** ability to commit changes to a single file via an HTTP request. |
| 2682 | */ |
| 2683 | struct CheckinWebInfo { |
| 2684 | Blob comment; /* Check-in comment text */ |
| 2685 | char *zMimetype; /* Mimetype of check-in command. May be NULL */ |
| 2686 | Manifest * pParent; /* parent checkin */ |
| 2687 | const char *zUser; /* User name */ |
| 2688 | char *zFilename; /* Name of single file to commit. */ |
| 2689 | Blob fileContent; /* Content of the modified file. */ |
| 2690 | Blob fileHash; /* Hash of this->fileContent */ |
| 2691 | }; |
| 2692 | #endif /* INTERFACE */ |
| 2693 | |
| 2694 | static void CheckinWebInfo_init( CheckinWebInfo * p ){ |
| 2695 | memset(p, 0, sizeof(struct CheckinWebInfo)); |
| 2696 | p->comment = p->fileContent = p->fileHash = empty_blob; |
| 2697 | } |
| 2698 | |
| 2699 | static void CheckinWebInfo_cleanup( CheckinWebInfo * p ){ |
| 2700 | blob_reset(&p->comment); |
| 2701 | blob_reset(&p->fileContent); |
| 2702 | blob_reset(&p->fileHash); |
| 2703 | if(p->pParent){ |
| 2704 | manifest_destroy(p->pParent); |
| 2705 | } |
| 2706 | fossil_free(p->zFilename); |
| 2707 | fossil_free(p->zMimetype); |
| 2708 | CheckinWebInfo_init(p); |
| 2709 | } |
| 2710 | |
| 2711 | /* |
| 2712 | ** Creates a manifest file, written to pOut, from the state in the |
| 2713 | ** fully-populated pCI argument. On error, returns non-0 and, if |
| 2714 | ** pErr is not NULL, writes an error message there. |
| 2715 | */ |
| 2716 | static int create_manifest_web( Blob * pOut, CheckinWebInfo * pCI, |
| 2717 | Blob * pErr){ |
| 2718 | Blob zCard = empty_blob; |
| 2719 | ManifestFile *zFile; |
| 2720 | int cmp = -99; |
| 2721 | const char *zPerm = ""; |
| 2722 | const char *zFilename = 0; |
| 2723 | const char *zUuid = 0; |
| 2724 | int (*fncmp)(char const *, char const *) = |
| 2725 | filenames_are_case_sensitive() |
| 2726 | ? fossil_strcmp |
| 2727 | : fossil_stricmp; |
| 2728 | |
| 2729 | #define mf_err(MSG) if(pErr) blob_append(pErr,MSG,-1); return 1 |
| 2730 | /* Potential TODOs include... |
| 2731 | ** - Create a delta manifest, if possible, rather than a baseline. |
| 2732 | ** - Enable adding of new files? It's implemented by disabled until |
| 2733 | ** we at least ensure that pCI->zFilename is a path-relative |
| 2734 | ** filename. |
| 2735 | ** - Maybe add support for tags. Those can be edited via /info page. |
| 2736 | ** - Check for a commit to a closed leaf and re-open it. |
| 2737 | */ |
| 2738 | blob_zero(pOut); |
| 2739 | if(blob_size(&pCI->comment)!=0){ |
| 2740 | blob_appendf(pOut, "C %F\n", blob_str(&pCI->comment)); |
| 2741 | }else{ |
| 2742 | blob_append(pOut, "C (no\\scomment)\n", 16); |
| 2743 | } |
| 2744 | blob_appendf(pOut, "D %z\n", date_in_standard_format("now")); |
| 2745 | |
| 2746 | manifest_file_rewind(pCI->pParent); |
| 2747 | while((zFile = manifest_file_next(pCI->pParent, 0))){ |
| 2748 | cmp = fncmp(zFile->zName, pCI->zFilename); |
| 2749 | if(cmp<0){ |
| 2750 | blob_appendf(pOut, "F %F %s%s\n", zFile->zName, zFile->zUuid, |
| 2751 | zFile->zPerm); |
| 2752 | }else{ |
| 2753 | break; |
| 2754 | } |
| 2755 | } |
| 2756 | if(cmp==0){ /* Match */ |
| 2757 | const int perm = manifest_file_mperm(zFile); |
| 2758 | if(PERM_LNK==perm){ |
| 2759 | mf_err("Cannot commit symlinks with this approach."); |
| 2760 | } |
| 2761 | zPerm = PERM_EXE==perm ? " x" : ""; |
| 2762 | zFilename = zFile->zName |
| 2763 | /* use original name in case of case difference */; |
| 2764 | zUuid = blob_str(&pCI->fileHash); |
| 2765 | }else{ |
| 2766 | /* This is a new file. */ |
| 2767 | zFilename = pCI->zFilename; |
| 2768 | zPerm = ""; |
| 2769 | zUuid = blob_str(&pCI->fileHash); |
| 2770 | if(cmp>0){ |
| 2771 | assert(zFile!=0); |
| 2772 | assert(pCI->pParent->iFile>0); |
| 2773 | --pCI->pParent->iFile |
| 2774 | /* so that the next step picks up that entry again */; |
| 2775 | } |
| 2776 | } |
| 2777 | assert(zFilename); |
| 2778 | assert(zUuid); |
| 2779 | assert(zPerm); |
| 2780 | blob_appendf(pOut, "F %F %s%s\n", zFilename, zUuid, zPerm); |
| 2781 | while((zFile = manifest_file_next(pCI->pParent, 0))){ |
| 2782 | cmp = fncmp(zFile->zName, pCI->zFilename); |
| 2783 | assert(cmp>0); |
| 2784 | if(cmp<=0){ |
| 2785 | mf_err("Mis-ordering of F-cards."); |
| 2786 | } |
| 2787 | blob_appendf(pOut, "F %F %s%s%s\n", |
| 2788 | zFile->zName, zFile->zUuid, |
| 2789 | (zFile->zPerm && *zFile->zPerm) ? " " : "", |
| 2790 | (zFile->zPerm && *zFile->zPerm) ? zFile->zPerm : ""); |
| 2791 | } |
| 2792 | |
| 2793 | if(pCI->zMimetype){ |
| 2794 | blob_appendf(pOut, "N %F\n", pCI->zMimetype); |
| 2795 | } |
| 2796 | |
| 2797 | blob_appendf(pOut, "P %z\n", |
| 2798 | db_text(0,"SELECT uuid FROM blob WHERE rid=%d", |
| 2799 | pCI->pParent->rid)); |
| 2800 | blob_appendf(pOut, "U %F\n", pCI->zUser); |
| 2801 | md5sum_blob(pOut, &zCard); |
| 2802 | blob_appendf(pOut, "Z %b\n", &zCard); |
| 2803 | blob_reset(&zCard); |
| 2804 | return 0; |
| 2805 | #undef mf_err |
| 2806 | } |
| 2807 | |
| 2808 | /* |
| 2809 | ** EXPERIMENTAL! A so-called "web checkin" is a slimmed-down form of |
| 2810 | ** the checkin command which accepts only a single file and is |
| 2811 | ** intended to accept edits to a file via the web interface. |
| 2812 | ** |
| 2813 | ** This routine uses the state from the given fully-populated pCI |
| 2814 | ** argument to add pCI->fileContent to the database, and create and |
| 2815 | ** save a manifest for that change. |
| 2816 | ** |
| 2817 | ** Fails fatally on error. If pRid is not NULL, the RID of the |
| 2818 | ** resulting manifest is written to *pRid. If bDryRun is true, |
| 2819 | ** it rolls back its transaction, else it commits as usual. |
| 2820 | ** |
| 2821 | */ |
| 2822 | void checkin_web( CheckinWebInfo * pCI, int *pRid, int bDryRun ){ |
| 2823 | Blob mf = empty_blob; |
| 2824 | Blob err = empty_blob; |
| 2825 | int rid = 0, frid = 0; |
| 2826 | const int isPrivate = content_is_private(pCI->pParent->rid); |
| 2827 | ManifestFile * zFile; |
| 2828 | |
| 2829 | db_begin_transaction(); |
| 2830 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", pCI->zUser) ){ |
| 2831 | fossil_fatal("no such user: %s", pCI->zUser); |
| 2832 | } |
| 2833 | manifest_file_rewind(pCI->pParent); |
| 2834 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2835 | if(!zFile){ |
| 2836 | fossil_fatal("File [%s] not found in manifest. " |
| 2837 | "Adding new files is currently not allowed.", |
| 2838 | pCI->zFilename); |
| 2839 | } |
| 2840 | if(create_manifest_web(&mf, pCI, &err)!=0){ |
| 2841 | fossil_fatal("create_manifest_web() failed: %B", &err); |
| 2842 | } |
| 2843 | frid = content_put_ex(&pCI->fileContent, blob_str(&pCI->fileHash), |
| 2844 | 0, 0, isPrivate); |
| 2845 | manifest_file_rewind(pCI->pParent); |
| 2846 | zFile = manifest_file_seek(pCI->pParent, pCI->zFilename, 0); |
| 2847 | if(zFile!=0){ |
| 2848 | int prevFRid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q", |
| 2849 | zFile->zUuid); |
| 2850 | assert(prevFRid>0); |
| 2851 | content_deltify(frid, &prevFRid, 1, 0); |
| 2852 | } |
| 2853 | rid = content_put_ex(&mf, 0, 0, 0, isPrivate); |
| 2854 | if(pRid!=0){ |
| 2855 | *pRid = rid; |
| 2856 | } |
| 2857 | fossil_print("Manifest:\n%b", &mf); |
| 2858 | manifest_crosslink(rid, &mf, 0); |
| 2859 | if(bDryRun){ |
| 2860 | fossil_print("Rolling back transaction.\n"); |
| 2861 | } |
| 2862 | db_end_transaction(bDryRun ? 1 : 0); |
| 2863 | blob_reset(&mf); |
| 2864 | } |
| 2865 | |
| 2866 | /* |
| 2867 | ** COMMAND: test-ci-web |
| 2868 | ** |
| 2869 | ** This is an on-going experiment, subject to change or removal at |
| 2870 | ** any time. |
| 2871 | ** |
| 2872 | ** Usage: %fossil ?OPTIONS? FILENAME |
| 2873 | ** |
| 2874 | ** where FILENAME is a repo-relative name as it would appear in the |
| 2875 | ** vfile table. |
| 2876 | */ |
| 2877 | void test_ci_one_cmd(){ |
| 2878 | CheckinWebInfo cinf; |
| 2879 | int parentVid = 0, newRid = 0; |
| 2880 | const char * zFilename; |
| 2881 | const char * zComment; |
| 2882 | const char * zAsFilename; |
| 2883 | int wetRunFlag = 0; |
| 2884 | |
| 2885 | if(g.argc<3){ |
| 2886 | usage("INFILE"); |
| 2887 | } |
| 2888 | db_find_and_open_repository(0, 0); |
| 2889 | wetRunFlag = find_option("wet-run",0,0)!=0; |
| 2890 | zComment = find_option("comment","m",1); |
| 2891 | zAsFilename = find_option("as",0,1); |
| 2892 | verify_all_options(); |
| 2893 | user_select(); |
| 2894 | |
| 2895 | zFilename = g.argv[2]; |
| 2896 | CheckinWebInfo_init(&cinf); |
| 2897 | blob_append(&cinf.comment, |
| 2898 | zComment ? zComment : "This is a test comment.", |
| 2899 | -1); |
| 2900 | cinf.zFilename = mprintf("%s", zAsFilename ? zAsFilename : zFilename); |
| 2901 | cinf.zUser = login_name(); |
| 2902 | |
| 2903 | cinf.pParent = manifest_get_by_name("trunk", &parentVid); |
| 2904 | assert(parentVid>0); |
| 2905 | assert(cinf.pParent!=0); |
| 2906 | blob_read_from_file(&cinf.fileContent, zFilename, |
| 2907 | ExtFILE/*may want to reconsider*/); |
| 2908 | sha3sum_init(256); |
| 2909 | sha3sum_step_blob(&cinf.fileContent); |
| 2910 | sha3sum_finish(&cinf.fileHash); |
| 2911 | checkin_web(&cinf, &newRid, wetRunFlag ? 0 : 1); |
| 2912 | CheckinWebInfo_cleanup(&cinf); |
| 2913 | if(wetRunFlag!=0 && newRid!=0 && g.localOpen!=0){ |
| 2914 | fossil_warning("The checkout state is now out of sync " |
| 2915 | "with regards to this commit. It needs to be " |
| 2916 | "'update'd or 'close'd and re-'open'ed."); |
| 2917 | /* vfile_check_signature(newRid,0); does not do the trick */ |
| 2918 | } |
| 2919 | } |
| 2920 |