Can I make this blind relative to the absolute conversion path (for the perforce depot path) better?

I need to "blindly" (i.e. without access to the file system, in this case the version control server) convert some relative paths to absolute paths. Therefore, I play with points and indices. For the curious, I have a log file created by another tool that sometimes outputs relative paths, and for performance reasons I don’t want to go to the version control server where the paths are located to check if they are valid and easily convert them to their absolute path equivalents .

I went through several (possibly stupid) iterations, trying to get it to work - basically several options for iterating over an array of folders and trying delete_at (index) and delete_at (index-1), but my index kept increasing while I was deleting array elements from underneath, which did not work for cases with multiple points. Any tips for improving it in general, or in particular the lack of support for dotdot serial points, would be welcome.

This currently works with my limited examples, but I think it can be improved. It cannot handle inconsistent ".." directories, and I probably do a lot of wasteful (and error prone) things that I probably don't need to do because I'm a bit hacked.

I found many examples of converting other types of relative paths using other languages, but none of them seemed to fit my situation.

These are my sample paths I need to convert from:

//depot/foo/../bar/single.c

//depot/foo/docs/../../other/double.c

//depot/foo/usr/bin/../../../else/more/triple.c

at

//depot/bar/single.c

//depot/other/double.c

//depot/else/more/triple.c

And my 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
+3
source share
3 answers

Do not reinvent the wheel ... File.expand_pathdoes it for you:

[
  '//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"]
+19
source

Why not just use 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"

For a DIY solution using arrays, this comes to mind (also works for your examples):

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('/')
+2
source

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)

:

//depot/bar/single.c
//depot/other/double.c
//depot/else/more/triple.c

Ruby.

+1

Source: https://habr.com/ru/post/1745498/


All Articles