Eu poderia fazer esse cego em relação à conversão absoluta do caminho (para os caminhos de depósito de Perforce) melhor?
-
26-09-2019 - |
Pergunta
Eu preciso "cegamente" (ou seja, sem acesso ao sistema de arquivos, neste caso o servidor de controle de origem) converte alguns caminhos relativos em caminhos absolutos. Então, eu estou brincando com Dotdots e índices. Para aqueles que estão curiosos, tenho um arquivo de log produzido pela ferramenta de outra pessoa que às vezes gera caminhos relativos e, por motivos de desempenho, não quero acessar o servidor de controle de origem onde os caminhos estão localizados para verificar se são válidos e mais converte -os facilmente em seus equivalentes absolutos.
Eu passei por várias iterações (provavelmente tolas) tentando fazer com que funcione - principalmente algumas variações de iterar sobre a matriz de pastas e tentar excluir_at (índice) e delete_at (índice -1), mas meu índice continuou incrementando enquanto Eu estava excluindo elementos da matriz fora de mim, o que não funcionou para casos com vários pontos. Quaisquer dicas sobre como melhorá-lo em geral ou especificamente a falta de suporte do DOTDOT não consecutivo seria bem-vindo.
Atualmente, isso está trabalhando com meus exemplos limitados, mas acho que poderia ser melhorado. Não pode lidar com diretórios não consecutivos '..', e provavelmente estou fazendo muitas coisas desperdiçadas (e propensas a erros) que provavelmente não preciso fazer porque sou um pouco hackeado.
Encontrei muitos exemplos de conversão de outros tipos de caminhos relativos usando outros idiomas, mas nenhum deles parecia se encaixar na minha situação.
Estes são os meus caminhos de exemplo que eu preciso converter, de:
//depot/foo/../bar/single.c
//depot/foo/docs/../../other/double.c
//depot/foo/usr/bin/../../../else/more/triple.c
para:
//depot/bar/single.c
//depot/other/double.c
//depot/else/more/triple.c
E meu script:
begin
paths = File.open(ARGV[0]).readlines
puts(paths)
new_paths = Array.new
paths.each { |path|
folders = path.split('/')
if ( folders.include?('..') )
num_dotdots = 0
first_dotdot = folders.index('..')
last_dotdot = folders.rindex('..')
folders.each { |item|
if ( item == '..' )
num_dotdots += 1
end
}
if ( first_dotdot and ( num_dotdots > 0 ) ) # this might be redundant?
folders.slice!(first_dotdot - num_dotdots..last_dotdot) # dependent on consecutive dotdots only
end
end
folders.map! { |elem|
if ( elem !~ /\n/ )
elem = elem + '/'
else
elem = elem
end
}
new_paths << folders.to_s
}
puts(new_paths)
end
Solução
Não vamos reinventar a roda ... File.expand_path
Faz isso por você:
[
'//depot/foo/../bar/single.c',
'//depot/foo/docs/../../other/double.c',
'//depot/foo/usr/bin/../../../else/more/triple.c'
].map {|p| File.expand_path(p) }
# ==> ["//depot/bar/single.c", "//depot/other/double.c", "//depot/else/more/triple.c"]
Outras dicas
Por que não apenas usar File.expand_path
:
irb(main):001:0> File.expand_path("//depot/foo/../bar/single.c")
=> "//depot/bar/single.c"
irb(main):002:0> File.expand_path("//depot/foo/docs/../../other/double.c")
=> "//depot/other/double.c"
irb(main):003:0> File.expand_path("//depot/foo/usr/bin/../../../else/more/triple.c")
=> "//depot/else/more/triple.c"
Para uma solução de bricolage usando matrizes, isso vem à mente (também funciona para seus exemplos):
absolute = []
relative = "//depot/foo/usr/bin/../../../else/more/triple.c".split('/')
relative.each { |d| if d == '..' then absolute.pop else absolute.push(d) end }
puts absolute.join('/')
Código Python:
paths = ['//depot/foo/../bar/single.c',
'//depot/foo/docs/../../other/double.c',
'//depot/foo/usr/bin/../../../else/more/triple.c']
def convert_path(path):
result = []
for item in path.split('/'):
if item == '..':
result.pop()
else:
result.append(item)
return '/'.join(result)
for path in paths:
print convert_path(path)
impressões:
//depot/bar/single.c
//depot/other/double.c
//depot/else/more/triple.c
Você pode usar o mesmo algoritmo em Ruby.