403
return initialize_fields_list(&fields_list, &initialized, "promisor.checkFields");
404
}
405
406
+static struct string_list *fields_stored(void)
407
+{
408
+ static struct string_list fields_list = STRING_LIST_INIT_NODUP;
409
+ static int initialized;
410
+
411
+ return initialize_fields_list(&fields_list, &initialized, "promisor.storeFields");
412
+}
413
+
414
/*
415
* Struct for promisor remotes involved in the "promisor-remote"
416
* protocol capability.
700
return info;
701
}
702
703
+static bool store_one_field(struct repository *repo, const char *remote_name,
704
+ const char *field_name, const char *field_key,
705
+ const char *advertised, const char *current)
706
+{
707
+ if (advertised && (!current || strcmp(current, advertised))) {
708
+ char *key = xstrfmt("remote.%s.%s", remote_name, field_key);
709
+
710
+ fprintf(stderr, _("Storing new %s from server for remote '%s'.\n"
711
+ " '%s' -> '%s'\n"),
712
+ field_name, remote_name,
713
+ current ? current : "",
714
+ advertised);
715
+
716
+ repo_config_set_gently(repo, key, advertised);
717
+ free(key);
718
+
719
+ return true;
720
+ }
721
+
722
+ return false;
723
+}
724
+
725
+/* Check that a filter is valid by parsing it */
726
+static bool valid_filter(const char *filter, const char *remote_name)
727
+{
728
+ struct list_objects_filter_options filter_opts = LIST_OBJECTS_FILTER_INIT;
729
+ struct strbuf err = STRBUF_INIT;
730
+ int res = gently_parse_list_objects_filter(&filter_opts, filter, &err);
731
+
732
+ if (res)
733
+ warning(_("invalid filter '%s' for remote '%s' "
734
+ "will not be stored: %s"),
735
+ filter, remote_name, err.buf);
736
+
737
+ list_objects_filter_release(&filter_opts);
738
+ strbuf_release(&err);
739
+
740
+ return !res;
741
+}
742
+
743
+/* Check that a token doesn't contain any control character */
744
+static bool valid_token(const char *token, const char *remote_name)
745
+{
746
+ const char *c = token;
747
+
748
+ for (; *c; c++)
749
+ if (iscntrl(*c)) {
750
+ warning(_("invalid token '%s' for remote '%s' "
751
+ "will not be stored"),
752
+ token, remote_name);
753
+ return false;
754
+ }
755
+
756
+ return true;
757
+}
758
+
759
+struct store_info {
760
+ struct repository *repo;
761
+ struct string_list config_info;
762
+ bool store_filter;
763
+ bool store_token;
764
+};
765
+
766
+static struct store_info *store_info_new(struct repository *repo)
767
+{
768
+ struct string_list *fields_to_store = fields_stored();
769
+ struct store_info *s = xmalloc(sizeof(*s));
770
+
771
+ s->repo = repo;
772
+
773
+ string_list_init_nodup(&s->config_info);
774
+ promisor_config_info_list(repo, &s->config_info, fields_to_store);
775
+ string_list_sort(&s->config_info);
776
+
777
+ s->store_filter = !!string_list_lookup(fields_to_store, promisor_field_filter);
778
+ s->store_token = !!string_list_lookup(fields_to_store, promisor_field_token);
779
+
780
+ return s;
781
+}
782
+
783
+static void store_info_free(struct store_info *s)
784
+{
785
+ if (s) {
786
+ promisor_info_list_clear(&s->config_info);
787
+ free(s);
788
+ }
789
+}
790
+
791
+static bool promisor_store_advertised_fields(struct promisor_info *advertised,
792
+ struct store_info *store_info)
793
+{
794
+ struct promisor_info *p;
795
+ struct string_list_item *item;
796
+ const char *remote_name = advertised->name;
797
+ bool reload_config = false;
798
+
799
+ if (!(store_info->store_filter || store_info->store_token))
800
+ return false;
801
+
802
+ /*
803
+ * Get existing config info for the advertised promisor
804
+ * remote. This ensures the remote is already configured on
805
+ * the client side.
806
+ */
807
+ item = string_list_lookup(&store_info->config_info, remote_name);
808
+
809
+ if (!item)
810
+ return false;
811
+
812
+ p = item->util;
813
+
814
+ if (store_info->store_filter && advertised->filter &&
815
+ valid_filter(advertised->filter, remote_name))
816
+ reload_config |= store_one_field(store_info->repo, remote_name,
817
+ "filter", promisor_field_filter,
818
+ advertised->filter, p->filter);
819
+
820
+ if (store_info->store_token && advertised->token &&
821
+ valid_token(advertised->token, remote_name))
822
+ reload_config |= store_one_field(store_info->repo, remote_name,
823
+ "token", promisor_field_token,
824
+ advertised->token, p->token);
825
+
826
+ return reload_config;
827
+}
828
+
829
static void filter_promisor_remote(struct repository *repo,
830
struct strvec *accepted,
831
const char *info)
834
enum accept_promisor accept = ACCEPT_NONE;
835
struct string_list config_info = STRING_LIST_INIT_NODUP;
836
struct string_list remote_info = STRING_LIST_INIT_DUP;
837
+ struct store_info *store_info = NULL;
838
struct string_list_item *item;
839
+ bool reload_config = false;
840
841
if (!repo_config_get_string_tmp(the_repository, "promisor.acceptfromserver", &accept_str)) {
842
if (!*accept_str || !strcasecmp("None", accept_str))
872
string_list_sort(&config_info);
873
}
874
739
- if (should_accept_remote(accept, advertised, &config_info))
875
+ if (should_accept_remote(accept, advertised, &config_info)) {
876
+ if (!store_info)
877
+ store_info = store_info_new(repo);
878
+ if (promisor_store_advertised_fields(advertised, store_info))
879
+ reload_config = true;
880
+
881
strvec_push(accepted, advertised->name);
882
+ }
883
884
promisor_info_free(advertised);
885
}
886
887
promisor_info_list_clear(&config_info);
888
string_list_clear(&remote_info, 0);
889
+ store_info_free(store_info);
890
+
891
+ if (reload_config)
892
+ repo_promisor_remote_reinit(repo);
893
}
894
895
char *promisor_remote_reply(const char *info)