Como escrever um “wrapper substituto” para uma função no FPATH?

3

No título, eu uso a expressão "overriding wrapper" para me referir a uma função foo que sobrescreve algumas funções da função original e chama essa função original (ou uma cópia dela) durante sua execução.

Eu encontrei os tópicos do Stack Exchange sobre isso (como este ), mas no meu caso eu tenho o requisito adicional de que tanto o% original foo quanto o foo substituto devem ser acessados através de FPATH e autoloaded. (A versão predominante presumivelmente apareceria mais cedo na sequência de pesquisa, ocultando assim a versão original.)

Existe uma maneira de fazer isso?

FWIW, no cenário particular com o qual estou lidando, a substituição de foo apenas atribui alguns valores não-padrão a algumas variáveis globais que o original se refere a fazer sua coisa.

    
por kjo 01.02.2018 / 21:52

2 respostas

2

Você pode usar esta função para carregar o código de uma função de um arquivo da mesma forma que autoload o faz, sem a restrição de que o nome do arquivo deve corresponder ao nome da função.

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

Veja como o código do wrapper se parece. $^fpath/somefunction(N) expande para a lista de definições de somefunction no caminho de carregamento ( $^fpath/somefunction expande para a lista de /dir/somefunction para cada /dir em $fpath e o qualificador de glob (N) restringe a expansão para arquivos existentes). Note que isto só funciona se você tiver um único nível de wrapper e o wrapper for no 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 "$@"
    
por 02.02.2018 / 01:15
3

Para substituir binários / init.d arquivos / scripts por um empacotador no Debian, tenho usado em produção há anos, com grande sucesso, desvios de arquivos.

Se você acabou de passar por um wrapper com o mesmo nome do arquivo original que deseja sombrear, o que acontece é que na próxima atualização do pacote correspondente, o wrapper provavelmente será reescrito pelo arquivo que você pretende substituir.

Então, por exemplo, para adicionar um wrapper para gcc , você faria:

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

Depois disso, você pode colocar seu wrapper em /usr/bin/gcc .

A partir daí, o antigo binário gcc será /usr/bin/gcc.real e, o mais importante, todas as atualizações futuras subseqüentes gcc feitas / instaladas pelo sistema Debian APT, instalarão novas instâncias de /usr/bin/gcc as /usr/bin/gcc.real e vai deixar o seu invólucro sem perturbações.

Veja Substituindo binários por dpkg-divert

De 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: usei essa técnica para adicionar opções extras aos scripts BIND e ISC-DHCP init.

    
por 01.02.2018 / 23:47