How to write an “overriding wrapper” for a function in FPATH?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
3
down vote

favorite












In the title, I use the expression "overriding wrapper" to refer to a function foo that overrides some original function falls, and calls this original function (or a copy of its) during its execution.



I have found Stack Exchange threads about this (like this one), but in my case I have the additional requirement that both the original foo as well as the overriding foo are meant to be accessible through FPATH, and autoloaded. (The overriding version presumably would appear earlier in the search sequence, thus shadowing the original version.)



Is there a way to do this?



FWIW, in the particular scenario I'm dealing with, the overriding foo just assigns some none-standard values to some global variables that the original refers to for doing its thing.







share|improve this question






















  • Are you using Debian?
    – Rui F Ribeiro
    Feb 1 at 21:45










  • @RuiFRibeiro: Both Debian and Centos
    – kjo
    Feb 1 at 21:52














up vote
3
down vote

favorite












In the title, I use the expression "overriding wrapper" to refer to a function foo that overrides some original function falls, and calls this original function (or a copy of its) during its execution.



I have found Stack Exchange threads about this (like this one), but in my case I have the additional requirement that both the original foo as well as the overriding foo are meant to be accessible through FPATH, and autoloaded. (The overriding version presumably would appear earlier in the search sequence, thus shadowing the original version.)



Is there a way to do this?



FWIW, in the particular scenario I'm dealing with, the overriding foo just assigns some none-standard values to some global variables that the original refers to for doing its thing.







share|improve this question






















  • Are you using Debian?
    – Rui F Ribeiro
    Feb 1 at 21:45










  • @RuiFRibeiro: Both Debian and Centos
    – kjo
    Feb 1 at 21:52












up vote
3
down vote

favorite









up vote
3
down vote

favorite











In the title, I use the expression "overriding wrapper" to refer to a function foo that overrides some original function falls, and calls this original function (or a copy of its) during its execution.



I have found Stack Exchange threads about this (like this one), but in my case I have the additional requirement that both the original foo as well as the overriding foo are meant to be accessible through FPATH, and autoloaded. (The overriding version presumably would appear earlier in the search sequence, thus shadowing the original version.)



Is there a way to do this?



FWIW, in the particular scenario I'm dealing with, the overriding foo just assigns some none-standard values to some global variables that the original refers to for doing its thing.







share|improve this question














In the title, I use the expression "overriding wrapper" to refer to a function foo that overrides some original function falls, and calls this original function (or a copy of its) during its execution.



I have found Stack Exchange threads about this (like this one), but in my case I have the additional requirement that both the original foo as well as the overriding foo are meant to be accessible through FPATH, and autoloaded. (The overriding version presumably would appear earlier in the search sequence, thus shadowing the original version.)



Is there a way to do this?



FWIW, in the particular scenario I'm dealing with, the overriding foo just assigns some none-standard values to some global variables that the original refers to for doing its thing.









share|improve this question













share|improve this question




share|improve this question








edited Feb 11 at 13:03









Rui F Ribeiro

35.1k1269113




35.1k1269113










asked Feb 1 at 20:52









kjo

3,85373458




3,85373458











  • Are you using Debian?
    – Rui F Ribeiro
    Feb 1 at 21:45










  • @RuiFRibeiro: Both Debian and Centos
    – kjo
    Feb 1 at 21:52
















  • Are you using Debian?
    – Rui F Ribeiro
    Feb 1 at 21:45










  • @RuiFRibeiro: Both Debian and Centos
    – kjo
    Feb 1 at 21:52















Are you using Debian?
– Rui F Ribeiro
Feb 1 at 21:45




Are you using Debian?
– Rui F Ribeiro
Feb 1 at 21:45












@RuiFRibeiro: Both Debian and Centos
– kjo
Feb 1 at 21:52




@RuiFRibeiro: Both Debian and Centos
– kjo
Feb 1 at 21:52










2 Answers
2






active

oldest

votes

















up vote
2
down vote



accepted










You can use this function to load the code of a function from a file in the same way that autoload does it, without the restriction that the file name has to match the function name.



## load_from FILE FUNCTION_NAME
load_from ()
eval "$2 () $(<$1) "



Here's how the wrapper code looks like. $^fpath/somefunction(N) expands to the list of definitions of somefunction in the load path ($^fpath/somefunction expands to the list of /dir/somefunction for each /dir in $fpath, and the glob qualifier (N) restricts the expansion to existing files). Note that this only works if you have a single level of wrapper and the wrapper is in the fpath.



#autoload somefunction
local some_parameter=overridden_value
local autoload_files
autoload_files=($^fpath/somefunction(N))
load_from $autoload_files[2] somefunction_wrapped
somefunction_wrapped "$@"





share|improve this answer






















  • Thanks! Did you mean to call the function autoload_from?
    – kjo
    Feb 2 at 13:55










  • Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
    – kjo
    Feb 2 at 14:32






  • 1




    @kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
    – Gilles
    Feb 2 at 21:07


















up vote
3
down vote













For replacing binaries/init.d files/scripts with a wrapper in Debian, I have used in production for years, with great success, file diversions.



If you just drop by a wrapper with the same name as the original file you want to shadow, what it happens is in the next update of the corresponding package the wrapper will be most probably rewritten by the file you intend to replace.



So for instance, for adding a wrapper for gcc, you would do:



sudo dpkg-divert --add --rename --divert /usr/bin/gcc.real /usr/bin/gcc


After that, you can place your wrapper at /usr/bin/gcc.



From then on, the old gcc binary will be /usr/bin/gcc.real, and most importantly, all the subsequent gcc future updates done/installed by Debian APT system, will install new instances of /usr/bin/gcc as /usr/bin/gcc.real and will leave your wrapper undisturbed.



See Replacing binaries with dpkg-divert



From man dpkg-divert




dpkg-divert is the utility used to set up and update the list of
diversions.



File diversions are a way of forcing dpkg(1) not to install a file
into its location, but to a diverted location. Diversions can be used
through the Debian package scripts to move a file away when it causes
a conflict. System administrators can also use it to override some
package's configuration file, or whenever some files (which aren't
marked as “conffiles”) need to be preserved by dpkg, when installing a
newer version of a package which contains those files.




PS I used this technique for adding extra options to the BIND and ISC-DHCP init scripts.






share|improve this answer






















  • I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
    – kjo
    Feb 2 at 22:08










Your Answer







StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f421291%2fhow-to-write-an-overriding-wrapper-for-a-function-in-fpath%23new-answer', 'question_page');

);

Post as a guest






























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote



accepted










You can use this function to load the code of a function from a file in the same way that autoload does it, without the restriction that the file name has to match the function name.



## load_from FILE FUNCTION_NAME
load_from ()
eval "$2 () $(<$1) "



Here's how the wrapper code looks like. $^fpath/somefunction(N) expands to the list of definitions of somefunction in the load path ($^fpath/somefunction expands to the list of /dir/somefunction for each /dir in $fpath, and the glob qualifier (N) restricts the expansion to existing files). Note that this only works if you have a single level of wrapper and the wrapper is in the fpath.



#autoload somefunction
local some_parameter=overridden_value
local autoload_files
autoload_files=($^fpath/somefunction(N))
load_from $autoload_files[2] somefunction_wrapped
somefunction_wrapped "$@"





share|improve this answer






















  • Thanks! Did you mean to call the function autoload_from?
    – kjo
    Feb 2 at 13:55










  • Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
    – kjo
    Feb 2 at 14:32






  • 1




    @kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
    – Gilles
    Feb 2 at 21:07















up vote
2
down vote



accepted










You can use this function to load the code of a function from a file in the same way that autoload does it, without the restriction that the file name has to match the function name.



## load_from FILE FUNCTION_NAME
load_from ()
eval "$2 () $(<$1) "



Here's how the wrapper code looks like. $^fpath/somefunction(N) expands to the list of definitions of somefunction in the load path ($^fpath/somefunction expands to the list of /dir/somefunction for each /dir in $fpath, and the glob qualifier (N) restricts the expansion to existing files). Note that this only works if you have a single level of wrapper and the wrapper is in the fpath.



#autoload somefunction
local some_parameter=overridden_value
local autoload_files
autoload_files=($^fpath/somefunction(N))
load_from $autoload_files[2] somefunction_wrapped
somefunction_wrapped "$@"





share|improve this answer






















  • Thanks! Did you mean to call the function autoload_from?
    – kjo
    Feb 2 at 13:55










  • Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
    – kjo
    Feb 2 at 14:32






  • 1




    @kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
    – Gilles
    Feb 2 at 21:07













up vote
2
down vote



accepted







up vote
2
down vote



accepted






You can use this function to load the code of a function from a file in the same way that autoload does it, without the restriction that the file name has to match the function name.



## load_from FILE FUNCTION_NAME
load_from ()
eval "$2 () $(<$1) "



Here's how the wrapper code looks like. $^fpath/somefunction(N) expands to the list of definitions of somefunction in the load path ($^fpath/somefunction expands to the list of /dir/somefunction for each /dir in $fpath, and the glob qualifier (N) restricts the expansion to existing files). Note that this only works if you have a single level of wrapper and the wrapper is in the fpath.



#autoload somefunction
local some_parameter=overridden_value
local autoload_files
autoload_files=($^fpath/somefunction(N))
load_from $autoload_files[2] somefunction_wrapped
somefunction_wrapped "$@"





share|improve this answer














You can use this function to load the code of a function from a file in the same way that autoload does it, without the restriction that the file name has to match the function name.



## load_from FILE FUNCTION_NAME
load_from ()
eval "$2 () $(<$1) "



Here's how the wrapper code looks like. $^fpath/somefunction(N) expands to the list of definitions of somefunction in the load path ($^fpath/somefunction expands to the list of /dir/somefunction for each /dir in $fpath, and the glob qualifier (N) restricts the expansion to existing files). Note that this only works if you have a single level of wrapper and the wrapper is in the fpath.



#autoload somefunction
local some_parameter=overridden_value
local autoload_files
autoload_files=($^fpath/somefunction(N))
load_from $autoload_files[2] somefunction_wrapped
somefunction_wrapped "$@"






share|improve this answer














share|improve this answer



share|improve this answer








edited Feb 2 at 22:05









kjo

3,85373458




3,85373458










answered Feb 2 at 0:15









Gilles

506k11910001528




506k11910001528











  • Thanks! Did you mean to call the function autoload_from?
    – kjo
    Feb 2 at 13:55










  • Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
    – kjo
    Feb 2 at 14:32






  • 1




    @kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
    – Gilles
    Feb 2 at 21:07

















  • Thanks! Did you mean to call the function autoload_from?
    – kjo
    Feb 2 at 13:55










  • Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
    – kjo
    Feb 2 at 14:32






  • 1




    @kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
    – Gilles
    Feb 2 at 21:07
















Thanks! Did you mean to call the function autoload_from?
– kjo
Feb 2 at 13:55




Thanks! Did you mean to call the function autoload_from?
– kjo
Feb 2 at 13:55












Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
– kjo
Feb 2 at 14:32




Also, the expression $fpath/somefunction(N[2]) is giving me trouble; I imaginge there's a typo in it somewhere, but I don't understand the syntax well enough to diagnose it. FWIW, if I inspect trace generated with set -x, I see that the $fpath/somefunction(N[2]) is getting replaced by my entire $fpath (space-separated).
– kjo
Feb 2 at 14:32




1




1




@kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
– Gilles
Feb 2 at 21:07





@kjo My bad, I fixed some errors and added some explanations. I adapted this heavily from a function in my .zshrc (which autoloads from a directory not on $fpath, rather than from a subsequent directory on $fpath as in your case) and left a few mistakes in the adaptation.
– Gilles
Feb 2 at 21:07













up vote
3
down vote













For replacing binaries/init.d files/scripts with a wrapper in Debian, I have used in production for years, with great success, file diversions.



If you just drop by a wrapper with the same name as the original file you want to shadow, what it happens is in the next update of the corresponding package the wrapper will be most probably rewritten by the file you intend to replace.



So for instance, for adding a wrapper for gcc, you would do:



sudo dpkg-divert --add --rename --divert /usr/bin/gcc.real /usr/bin/gcc


After that, you can place your wrapper at /usr/bin/gcc.



From then on, the old gcc binary will be /usr/bin/gcc.real, and most importantly, all the subsequent gcc future updates done/installed by Debian APT system, will install new instances of /usr/bin/gcc as /usr/bin/gcc.real and will leave your wrapper undisturbed.



See Replacing binaries with dpkg-divert



From man dpkg-divert




dpkg-divert is the utility used to set up and update the list of
diversions.



File diversions are a way of forcing dpkg(1) not to install a file
into its location, but to a diverted location. Diversions can be used
through the Debian package scripts to move a file away when it causes
a conflict. System administrators can also use it to override some
package's configuration file, or whenever some files (which aren't
marked as “conffiles”) need to be preserved by dpkg, when installing a
newer version of a package which contains those files.




PS I used this technique for adding extra options to the BIND and ISC-DHCP init scripts.






share|improve this answer






















  • I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
    – kjo
    Feb 2 at 22:08














up vote
3
down vote













For replacing binaries/init.d files/scripts with a wrapper in Debian, I have used in production for years, with great success, file diversions.



If you just drop by a wrapper with the same name as the original file you want to shadow, what it happens is in the next update of the corresponding package the wrapper will be most probably rewritten by the file you intend to replace.



So for instance, for adding a wrapper for gcc, you would do:



sudo dpkg-divert --add --rename --divert /usr/bin/gcc.real /usr/bin/gcc


After that, you can place your wrapper at /usr/bin/gcc.



From then on, the old gcc binary will be /usr/bin/gcc.real, and most importantly, all the subsequent gcc future updates done/installed by Debian APT system, will install new instances of /usr/bin/gcc as /usr/bin/gcc.real and will leave your wrapper undisturbed.



See Replacing binaries with dpkg-divert



From man dpkg-divert




dpkg-divert is the utility used to set up and update the list of
diversions.



File diversions are a way of forcing dpkg(1) not to install a file
into its location, but to a diverted location. Diversions can be used
through the Debian package scripts to move a file away when it causes
a conflict. System administrators can also use it to override some
package's configuration file, or whenever some files (which aren't
marked as “conffiles”) need to be preserved by dpkg, when installing a
newer version of a package which contains those files.




PS I used this technique for adding extra options to the BIND and ISC-DHCP init scripts.






share|improve this answer






















  • I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
    – kjo
    Feb 2 at 22:08












up vote
3
down vote










up vote
3
down vote









For replacing binaries/init.d files/scripts with a wrapper in Debian, I have used in production for years, with great success, file diversions.



If you just drop by a wrapper with the same name as the original file you want to shadow, what it happens is in the next update of the corresponding package the wrapper will be most probably rewritten by the file you intend to replace.



So for instance, for adding a wrapper for gcc, you would do:



sudo dpkg-divert --add --rename --divert /usr/bin/gcc.real /usr/bin/gcc


After that, you can place your wrapper at /usr/bin/gcc.



From then on, the old gcc binary will be /usr/bin/gcc.real, and most importantly, all the subsequent gcc future updates done/installed by Debian APT system, will install new instances of /usr/bin/gcc as /usr/bin/gcc.real and will leave your wrapper undisturbed.



See Replacing binaries with dpkg-divert



From man dpkg-divert




dpkg-divert is the utility used to set up and update the list of
diversions.



File diversions are a way of forcing dpkg(1) not to install a file
into its location, but to a diverted location. Diversions can be used
through the Debian package scripts to move a file away when it causes
a conflict. System administrators can also use it to override some
package's configuration file, or whenever some files (which aren't
marked as “conffiles”) need to be preserved by dpkg, when installing a
newer version of a package which contains those files.




PS I used this technique for adding extra options to the BIND and ISC-DHCP init scripts.






share|improve this answer














For replacing binaries/init.d files/scripts with a wrapper in Debian, I have used in production for years, with great success, file diversions.



If you just drop by a wrapper with the same name as the original file you want to shadow, what it happens is in the next update of the corresponding package the wrapper will be most probably rewritten by the file you intend to replace.



So for instance, for adding a wrapper for gcc, you would do:



sudo dpkg-divert --add --rename --divert /usr/bin/gcc.real /usr/bin/gcc


After that, you can place your wrapper at /usr/bin/gcc.



From then on, the old gcc binary will be /usr/bin/gcc.real, and most importantly, all the subsequent gcc future updates done/installed by Debian APT system, will install new instances of /usr/bin/gcc as /usr/bin/gcc.real and will leave your wrapper undisturbed.



See Replacing binaries with dpkg-divert



From man dpkg-divert




dpkg-divert is the utility used to set up and update the list of
diversions.



File diversions are a way of forcing dpkg(1) not to install a file
into its location, but to a diverted location. Diversions can be used
through the Debian package scripts to move a file away when it causes
a conflict. System administrators can also use it to override some
package's configuration file, or whenever some files (which aren't
marked as “conffiles”) need to be preserved by dpkg, when installing a
newer version of a package which contains those files.




PS I used this technique for adding extra options to the BIND and ISC-DHCP init scripts.







share|improve this answer














share|improve this answer



share|improve this answer








edited Feb 2 at 23:13

























answered Feb 1 at 22:47









Rui F Ribeiro

35.1k1269113




35.1k1269113











  • I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
    – kjo
    Feb 2 at 22:08
















  • I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
    – kjo
    Feb 2 at 22:08















I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
– kjo
Feb 2 at 22:08




I'm looking for something that does not depend on the distro, but, nonetheless, dpkg-divert does look like a very useful tool. Thanks!
– kjo
Feb 2 at 22:08












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f421291%2fhow-to-write-an-overriding-wrapper-for-a-function-in-fpath%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Peggy Mitchell

Palaiologos

The Forum (Inglewood, California)