@@ -63,3 +63,173 @@ func StartPlugin(pluginType PluginType, pluginName string) (Plugin, error) {
6363
6464 return p , nil
6565}
66+
67+ // SetPluginOption sets the value of a named option for a plugin entry. This
68+ // is used by callers that need to programmatically override plugin defaults
69+ // (for example to set data-dir before starting a plugin). It returns an error
70+ // if the plugin or option is not found or if the value type is incompatible.
71+ // NOTE: This function accesses the global pluginEntries slice without
72+ // synchronization. It should only be called during initialization or in
73+ // single-threaded contexts to avoid race conditions.
74+ // NOTE: This function writes directly to plugin option destinations (e.g.,
75+ // cmdlineOptions fields) without acquiring the plugin's cmdlineOptionsMutex.
76+ // It must be called before any plugin instantiation to avoid data races with
77+ // concurrent reads in NewFromCmdlineOptions.
78+ func SetPluginOption (
79+ pluginType PluginType ,
80+ pluginName string ,
81+ optionName string ,
82+ value any ,
83+ ) error {
84+ for i := range pluginEntries {
85+ p := & pluginEntries [i ]
86+ if p .Type != pluginType || p .Name != pluginName {
87+ continue
88+ }
89+ for _ , opt := range p .Options {
90+ if opt .Name != optionName {
91+ continue
92+ }
93+ // Perform a type-checked assignment into the Dest pointer
94+ switch opt .Type {
95+ case PluginOptionTypeString :
96+ v , ok := value .(string )
97+ if ! ok {
98+ return fmt .Errorf (
99+ "invalid type for option %s: expected string" ,
100+ optionName ,
101+ )
102+ }
103+ if opt .Dest == nil {
104+ return fmt .Errorf (
105+ "nil destination for option %s" ,
106+ optionName ,
107+ )
108+ }
109+ dest , ok := opt .Dest .(* string )
110+ if ! ok {
111+ return fmt .Errorf (
112+ "invalid destination type for option %s: expected *string" ,
113+ optionName ,
114+ )
115+ }
116+ if dest == nil {
117+ return fmt .Errorf (
118+ "nil destination pointer for option %s" ,
119+ optionName ,
120+ )
121+ }
122+ * dest = v
123+ return nil
124+ case PluginOptionTypeBool :
125+ v , ok := value .(bool )
126+ if ! ok {
127+ return fmt .Errorf (
128+ "invalid type for option %s: expected bool" ,
129+ optionName ,
130+ )
131+ }
132+ if opt .Dest == nil {
133+ return fmt .Errorf (
134+ "nil destination for option %s" ,
135+ optionName ,
136+ )
137+ }
138+ dest , ok := opt .Dest .(* bool )
139+ if ! ok {
140+ return fmt .Errorf (
141+ "invalid destination type for option %s: expected *bool" ,
142+ optionName ,
143+ )
144+ }
145+ if dest == nil {
146+ return fmt .Errorf (
147+ "nil destination pointer for option %s" ,
148+ optionName ,
149+ )
150+ }
151+ * dest = v
152+ return nil
153+ case PluginOptionTypeInt :
154+ v , ok := value .(int )
155+ if ! ok {
156+ return fmt .Errorf (
157+ "invalid type for option %s: expected int" ,
158+ optionName ,
159+ )
160+ }
161+ if opt .Dest == nil {
162+ return fmt .Errorf (
163+ "nil destination for option %s" ,
164+ optionName ,
165+ )
166+ }
167+ dest , ok := opt .Dest .(* int )
168+ if ! ok {
169+ return fmt .Errorf (
170+ "invalid destination type for option %s: expected *int" ,
171+ optionName ,
172+ )
173+ }
174+ if dest == nil {
175+ return fmt .Errorf (
176+ "nil destination pointer for option %s" ,
177+ optionName ,
178+ )
179+ }
180+ * dest = v
181+ return nil
182+ case PluginOptionTypeUint :
183+ // accept uint64 or int
184+ switch tv := value .(type ) {
185+ case uint64 :
186+ if opt .Dest == nil {
187+ return fmt .Errorf ("nil destination for option %s" , optionName )
188+ }
189+ dest , ok := opt .Dest .(* uint64 )
190+ if ! ok {
191+ return fmt .Errorf ("invalid destination type for option %s: expected *uint64" , optionName )
192+ }
193+ if dest == nil {
194+ return fmt .Errorf ("nil destination pointer for option %s" , optionName )
195+ }
196+ * dest = tv
197+ return nil
198+ case int :
199+ if tv < 0 {
200+ return fmt .Errorf ("invalid value for option %s: negative int" , optionName )
201+ }
202+ if opt .Dest == nil {
203+ return fmt .Errorf ("nil destination for option %s" , optionName )
204+ }
205+ dest , ok := opt .Dest .(* uint64 )
206+ if ! ok {
207+ return fmt .Errorf ("invalid destination type for option %s: expected *uint64" , optionName )
208+ }
209+ if dest == nil {
210+ return fmt .Errorf ("nil destination pointer for option %s" , optionName )
211+ }
212+ * dest = uint64 (tv )
213+ return nil
214+ default :
215+ return fmt .Errorf ("invalid type for option %s: expected uint64 or int" , optionName )
216+ }
217+ default :
218+ return fmt .Errorf (
219+ "unknown plugin option type %d for option %s" ,
220+ opt .Type ,
221+ optionName ,
222+ )
223+ }
224+ }
225+ // Option not found for this plugin: treat as non-fatal. This allows
226+ // callers to attempt to set options that may not exist for all
227+ // implementations (for example `data-dir` may not be relevant).
228+ return nil
229+ }
230+ return fmt .Errorf (
231+ "plugin %s of type %s not found" ,
232+ pluginName ,
233+ PluginTypeName (pluginType ),
234+ )
235+ }
0 commit comments