| | @@ -3647,66 +3647,79 @@ |
| 3647 | 3647 | ** |
| 3648 | 3648 | ** If the zNonVersionedSetting parameter is not NULL then it holds the |
| 3649 | 3649 | ** non-versioned value for this setting. If both a versioned and a |
| 3650 | 3650 | ** non-versioned value exist and are not equal, then a warning message |
| 3651 | 3651 | ** might be generated. |
| 3652 | +** |
| 3653 | +** zCkin is normally NULL. In that case, the versioned setting is |
| 3654 | +** take from the local check-out, if a local checkout exists, or from |
| 3655 | +** checkin named by the g.zOpenRevision global variable. If zCkin is |
| 3656 | +** not NULL, then zCkin is the name of the specific checkin from which |
| 3657 | +** versioned setting value is taken. When zCkin is not NULL, the cache |
| 3658 | +** is bypassed. |
| 3652 | 3659 | */ |
| 3653 | | -char *db_get_versioned(const char *zName, char *zNonVersionedSetting){ |
| 3660 | +char *db_get_versioned( |
| 3661 | + const char *zName, |
| 3662 | + char *zNonVersionedSetting, |
| 3663 | + const char *zCkin |
| 3664 | +){ |
| 3654 | 3665 | char *zVersionedSetting = 0; |
| 3655 | 3666 | int noWarn = 0; |
| 3656 | 3667 | int found = 0; |
| 3657 | 3668 | struct _cacheEntry { |
| 3658 | 3669 | struct _cacheEntry *next; |
| 3659 | 3670 | const char *zName, *zValue; |
| 3660 | 3671 | } *cacheEntry = 0; |
| 3661 | 3672 | static struct _cacheEntry *cache = 0; |
| 3662 | 3673 | |
| 3663 | | - if( !g.localOpen && g.zOpenRevision==0 ) return zNonVersionedSetting; |
| 3674 | + if( !g.localOpen && g.zOpenRevision==0 && zCkin==0 ){ |
| 3675 | + return zNonVersionedSetting; |
| 3676 | + } |
| 3677 | + |
| 3664 | 3678 | /* Look up name in cache */ |
| 3665 | | - cacheEntry = cache; |
| 3666 | | - while( cacheEntry!=0 ){ |
| 3667 | | - if( fossil_strcmp(cacheEntry->zName, zName)==0 ){ |
| 3668 | | - zVersionedSetting = fossil_strdup(cacheEntry->zValue); |
| 3669 | | - break; |
| 3670 | | - } |
| 3671 | | - cacheEntry = cacheEntry->next; |
| 3672 | | - } |
| 3679 | + if( zCkin==0 ){ |
| 3680 | + cacheEntry = cache; |
| 3681 | + while( cacheEntry!=0 ){ |
| 3682 | + if( fossil_strcmp(cacheEntry->zName, zName)==0 ){ |
| 3683 | + zVersionedSetting = fossil_strdup(cacheEntry->zValue); |
| 3684 | + break; |
| 3685 | + } |
| 3686 | + cacheEntry = cacheEntry->next; |
| 3687 | + } |
| 3688 | + } |
| 3689 | + |
| 3673 | 3690 | /* Attempt to read value from file in check-out if there wasn't a cache hit.*/ |
| 3674 | 3691 | if( cacheEntry==0 ){ |
| 3675 | 3692 | Blob versionedPathname; |
| 3676 | 3693 | Blob setting; |
| 3677 | | - blob_zero(&versionedPathname); |
| 3678 | | - blob_zero(&setting); |
| 3679 | | - blob_appendf(&versionedPathname, "%s.fossil-settings/%s", |
| 3680 | | - g.zLocalRoot, zName); |
| 3681 | | - if( !g.localOpen ){ |
| 3682 | | - /* Repository is in the process of being opened, but files have not been |
| 3683 | | - * written to disk. Load from the database. */ |
| 3684 | | - Blob noWarnFile; |
| 3685 | | - if( historical_blob(g.zOpenRevision, blob_str(&versionedPathname), |
| 3686 | | - &setting, 0) ){ |
| 3687 | | - found = 1; |
| 3688 | | - } |
| 3689 | | - /* See if there's a no-warn flag */ |
| 3690 | | - blob_append(&versionedPathname, ".no-warn", -1); |
| 3691 | | - blob_zero(&noWarnFile); |
| 3692 | | - if( historical_blob(g.zOpenRevision, blob_str(&versionedPathname), |
| 3693 | | - &noWarnFile, 0) ){ |
| 3694 | | - noWarn = 1; |
| 3695 | | - } |
| 3696 | | - blob_reset(&noWarnFile); |
| 3697 | | - }else if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 3698 | | - /* File exists, and contains the value for this setting. Load from |
| 3699 | | - ** the file. */ |
| 3700 | | - const char *zFile = blob_str(&versionedPathname); |
| 3701 | | - if( blob_read_from_file(&setting, zFile, ExtFILE)>=0 ){ |
| 3702 | | - found = 1; |
| 3703 | | - } |
| 3704 | | - /* See if there's a no-warn flag */ |
| 3705 | | - blob_append(&versionedPathname, ".no-warn", -1); |
| 3706 | | - if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 3707 | | - noWarn = 1; |
| 3694 | + blob_init(&versionedPathname, 0, 0); |
| 3695 | + blob_init(&setting, 0, 0); |
| 3696 | + if( !g.localOpen || zCkin!=0 ){ |
| 3697 | + /* Repository is in the process of being opened, but files have not been |
| 3698 | + * written to disk. Load from the database. */ |
| 3699 | + blob_appendf(&versionedPathname, ".fossil-settings/%s", zName); |
| 3700 | + if( historical_blob(zCkin ? zCkin : g.zOpenRevision, |
| 3701 | + blob_str(&versionedPathname), |
| 3702 | + &setting, 0) |
| 3703 | + ){ |
| 3704 | + found = 1; |
| 3705 | + } |
| 3706 | + }else{ |
| 3707 | + blob_appendf(&versionedPathname, "%s.fossil-settings/%s", |
| 3708 | + g.zLocalRoot, zName); |
| 3709 | + if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 3710 | + /* File exists, and contains the value for this setting. Load from |
| 3711 | + ** the file. */ |
| 3712 | + const char *zFile = blob_str(&versionedPathname); |
| 3713 | + if( blob_read_from_file(&setting, zFile, ExtFILE)>=0 ){ |
| 3714 | + found = 1; |
| 3715 | + } |
| 3716 | + /* See if there's a no-warn flag */ |
| 3717 | + blob_append(&versionedPathname, ".no-warn", -1); |
| 3718 | + if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 3719 | + noWarn = 1; |
| 3720 | + } |
| 3708 | 3721 | } |
| 3709 | 3722 | } |
| 3710 | 3723 | blob_reset(&versionedPathname); |
| 3711 | 3724 | if( found ){ |
| 3712 | 3725 | blob_strip_comment_lines(&setting, &setting); |
| | @@ -3713,20 +3726,27 @@ |
| 3713 | 3726 | blob_trim(&setting); /* Avoid non-obvious problems with line endings |
| 3714 | 3727 | ** on boolean properties */ |
| 3715 | 3728 | zVersionedSetting = fossil_strdup(blob_str(&setting)); |
| 3716 | 3729 | } |
| 3717 | 3730 | blob_reset(&setting); |
| 3731 | + |
| 3718 | 3732 | /* Store result in cache, which can be the value or 0 if not found */ |
| 3719 | | - cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(struct _cacheEntry)); |
| 3720 | | - cacheEntry->next = cache; |
| 3721 | | - cacheEntry->zName = zName; |
| 3722 | | - cacheEntry->zValue = fossil_strdup(zVersionedSetting); |
| 3723 | | - cache = cacheEntry; |
| 3733 | + if( zCkin==0 ){ |
| 3734 | + cacheEntry = (struct _cacheEntry*)fossil_malloc(sizeof(*cacheEntry)); |
| 3735 | + cacheEntry->next = cache; |
| 3736 | + cacheEntry->zName = zName; |
| 3737 | + cacheEntry->zValue = fossil_strdup(zVersionedSetting); |
| 3738 | + cache = cacheEntry; |
| 3739 | + } |
| 3724 | 3740 | } |
| 3741 | + |
| 3725 | 3742 | /* Display a warning? */ |
| 3726 | | - if( zVersionedSetting!=0 && zNonVersionedSetting!=0 |
| 3727 | | - && zNonVersionedSetting[0]!='\0' && !noWarn |
| 3743 | + if( zVersionedSetting!=0 |
| 3744 | + && zNonVersionedSetting!=0 |
| 3745 | + && zNonVersionedSetting[0]!='\0' |
| 3746 | + && zCkin==0 |
| 3747 | + && !noWarn |
| 3728 | 3748 | ){ |
| 3729 | 3749 | /* There's a versioned setting, and a non-versioned setting. Tell |
| 3730 | 3750 | ** the user about the conflict */ |
| 3731 | 3751 | fossil_warning( |
| 3732 | 3752 | "setting %s has both versioned and non-versioned values: using " |
| | @@ -3735,10 +3755,11 @@ |
| 3735 | 3755 | "\"%/.fossil-settings/%s.no-warn\" in the check-out root, or delete " |
| 3736 | 3756 | "the non-versioned setting with \"fossil unset %s\")", zName, |
| 3737 | 3757 | g.zLocalRoot, zName, g.zLocalRoot, zName, zName |
| 3738 | 3758 | ); |
| 3739 | 3759 | } |
| 3760 | + |
| 3740 | 3761 | /* Prefer the versioned setting */ |
| 3741 | 3762 | return ( zVersionedSetting!=0 ) ? zVersionedSetting : zNonVersionedSetting; |
| 3742 | 3763 | } |
| 3743 | 3764 | |
| 3744 | 3765 | |
| | @@ -3778,11 +3799,11 @@ |
| 3778 | 3799 | } |
| 3779 | 3800 | if( pSetting!=0 && pSetting->versionable ){ |
| 3780 | 3801 | /* This is a versionable setting, try and get the info from a |
| 3781 | 3802 | ** checked-out file */ |
| 3782 | 3803 | char * zZ = z; |
| 3783 | | - z = db_get_versioned(zName, z); |
| 3804 | + z = db_get_versioned(zName, z, 0); |
| 3784 | 3805 | if(zZ != z){ |
| 3785 | 3806 | fossil_free(zZ); |
| 3786 | 3807 | } |
| 3787 | 3808 | } |
| 3788 | 3809 | if( z==0 ){ |
| | @@ -3919,11 +3940,11 @@ |
| 3919 | 3940 | } |
| 3920 | 3941 | fossil_free(zVal); |
| 3921 | 3942 | return dflt; |
| 3922 | 3943 | } |
| 3923 | 3944 | int db_get_versioned_boolean(const char *zName, int dflt){ |
| 3924 | | - char *zVal = db_get_versioned(zName, 0); |
| 3945 | + char *zVal = db_get_versioned(zName, 0, 0); |
| 3925 | 3946 | if( zVal==0 ) return dflt; |
| 3926 | 3947 | if( is_truth(zVal) ) return 1; |
| 3927 | 3948 | if( is_false(zVal) ) return 0; |
| 3928 | 3949 | return dflt; |
| 3929 | 3950 | } |
| | @@ -4048,14 +4069,30 @@ |
| 4048 | 4069 | ** Get the manifest setting. For backwards compatibility first check if the |
| 4049 | 4070 | ** value is a boolean. If it's not a boolean, treat each character as a flag |
| 4050 | 4071 | ** to enable a manifest type. This system puts certain boundary conditions on |
| 4051 | 4072 | ** which letters can be used to represent flags (any permutation of flags must |
| 4052 | 4073 | ** not be able to fully form one of the boolean values). |
| 4074 | +** |
| 4075 | +** "manifest" is a versionable setting. But we do not issue a warning |
| 4076 | +** if there is a conflict. Instead, the value returned is the value for |
| 4077 | +** the versioned setting if the versioned setting exists, or the ordinary |
| 4078 | +** setting otherwise. |
| 4079 | +** |
| 4080 | +** The argument zCkin is the specific check-in for which we want the |
| 4081 | +** manifest setting. |
| 4053 | 4082 | */ |
| 4054 | | -int db_get_manifest_setting(void){ |
| 4083 | +int db_get_manifest_setting(const char *zCkin){ |
| 4055 | 4084 | int flg; |
| 4056 | | - char *zVal = db_get("manifest", 0); |
| 4085 | + char *zVal; |
| 4086 | + |
| 4087 | + /* Look for the versioned setting first */ |
| 4088 | + zVal = db_get_versioned("manifest", 0, zCkin); |
| 4089 | + |
| 4090 | + if( zVal==0 && g.repositoryOpen ){ |
| 4091 | + /* No versioned setting, look for the repository setting second */ |
| 4092 | + zVal = db_text(0, "SELECT value FROM config WHERE name='manifest'"); |
| 4093 | + } |
| 4057 | 4094 | if( zVal==0 || is_false(zVal) ){ |
| 4058 | 4095 | return 0; |
| 4059 | 4096 | }else if( is_truth(zVal) ){ |
| 4060 | 4097 | return MFESTFLG_RAW|MFESTFLG_UUID; |
| 4061 | 4098 | } |
| | @@ -4068,10 +4105,37 @@ |
| 4068 | 4105 | } |
| 4069 | 4106 | zVal++; |
| 4070 | 4107 | } |
| 4071 | 4108 | return flg; |
| 4072 | 4109 | } |
| 4110 | + |
| 4111 | +/* |
| 4112 | +** COMMAND: test-manifest-setting |
| 4113 | +** |
| 4114 | +** Usage: %fossil test-manifest-setting VERSION VERSION ... |
| 4115 | +** |
| 4116 | +** Display the value for the "manifest" setting for various versions |
| 4117 | +** of the repository. |
| 4118 | +*/ |
| 4119 | +void test_manfest_setting_cmd(void){ |
| 4120 | + int i; |
| 4121 | + db_find_and_open_repository(0, 0); |
| 4122 | + for(i=2; i<g.argc; i++){ |
| 4123 | + int m = db_get_manifest_setting(g.argv[i]); |
| 4124 | + fossil_print("%s:\n", g.argv[i]); |
| 4125 | + fossil_print(" flags = 0x%02x\n", m); |
| 4126 | + if( m & MFESTFLG_RAW ){ |
| 4127 | + fossil_print(" manifest\n"); |
| 4128 | + } |
| 4129 | + if( m & MFESTFLG_UUID ){ |
| 4130 | + fossil_print(" manifest.uuid\n"); |
| 4131 | + } |
| 4132 | + if( m & MFESTFLG_TAGS ){ |
| 4133 | + fossil_print(" manifest.tags\n"); |
| 4134 | + } |
| 4135 | + } |
| 4136 | +} |
| 4073 | 4137 | |
| 4074 | 4138 | |
| 4075 | 4139 | /* |
| 4076 | 4140 | ** Record the name of a local repository in the global_config() database. |
| 4077 | 4141 | ** The repository filename %s is recorded as an entry with a "name" field |
| | @@ -4391,11 +4455,11 @@ |
| 4391 | 4455 | versioned = 1; |
| 4392 | 4456 | } |
| 4393 | 4457 | blob_reset(&versionedPathname); |
| 4394 | 4458 | } |
| 4395 | 4459 | if( valueOnly && versioned ){ |
| 4396 | | - fossil_print("%s\n", db_get_versioned(pSetting->name, NULL)); |
| 4460 | + fossil_print("%s\n", db_get_versioned(pSetting->name, NULL, NULL)); |
| 4397 | 4461 | return; |
| 4398 | 4462 | } |
| 4399 | 4463 | if( g.repositoryOpen ){ |
| 4400 | 4464 | db_prepare(&q, |
| 4401 | 4465 | "SELECT '(local)', value FROM config WHERE name=%Q" |
| 4402 | 4466 | |