From: Garrett C. <yan...@gm...> - 2010-01-18 01:16:50
|
2010/1/16 Garrett Cooper <yan...@gm...>: > 2010/1/15 Mike Frysinger <va...@ge...>: >> On Friday 15 January 2010 17:07:48 Garrett Cooper wrote: >>> Shortly after I sent out this email, I received some helpful replies >>> as to why my code wasn't working. It turns out that the curly bracket >>> regexp quantifier operators available in many other popular >>> implementations of regexps (perl, python, tcl) isn't supported in awk. >>> Here's the new patch with less bloat. >> >> the patch itself is word wrapped in the e-mail though :( >> >>> +_abspath() { >>> + echo "$@" | awk '{ sub(/\/$/, ""); while (gsub(/\/\//, "/")) { }; >>> while (gsub(/\/[^\/]+\/\.\.\/?/, "/")) { }; while (gsub(/\/\.\//, >>> "/")) { } print }' >>> +} >> >> it's easy to line wrap awk scripts, and this sucker really needs it >> >> btw, this doesnt quite handle: >> /a/b/c/.././ >> >> how about this (largely untested) sed: >> sed -r -e 's:/+[.]/+:/:g' -e 's:(^|/+[^/]*)/+[.][.]/+:/:g' -e 's:/+$::' >> >>> --- /dev/null 1 Jan 1970 00:00:00 -0000 >>> +++ tests/test_abspath.sh 15 Jan 2010 22:04:59 -0000 >>> +# NOTE (garrcoop): I usually don't use bashisms, but it was just easier to >>> +# express these values as an array of values instead of one whacky long >>> +# string. >>> +test_strings=( foo/bar /foo/bar /foo/../bar /foo/bar/../baz >>> /foo/bar/../baz/ /foo/../bar/ /foo/../bar/.. /foo/../bar/../ >>> /foo/bar/../baz /foo/./bar /./foo/./bar /foo//bar //foo/bar >>> //////foo/bar /foo/////bar ) >>> +expected_strings=( foo/bar /foo/bar /bar /foo/baz >>> /foo/baz /bar / / /foo/baz >>> /foo/bar /foo/bar /foo/bar /foo/bar /foo/bar >>> /foo/bar ) >> >> probably be good if the source were better wrapped >> >> however, two parallel arrays makes it hard to correlate the input/expected >> values. how about something like: >> set -- \ >> foo/bar:foo/bar \ >> /foo/bar:/foo/bar \ >> /foo/../bar:/bar \ >> ........... >> >> then you can easily do: >> for test in "$@" ; do >> input=${test%:*} >> expect=${test#*:} >> ... >> done >> >> this should be POSIX and avoid /bin/bash > > Version 2: > > 1. Incorporate comments from Mike F. > 2. Resolve a negative testcase failure. > > gcooper@orangebox /scratch/ltp $ scripts/tests/test_abspath.sh > test_abspath 1 TPASS : Test string matches expected string > _abspath(foo/bar) => foo/bar == foo/bar) > test_abspath 2 TPASS : Test string matches expected string > _abspath(/foo/bar) => /foo/bar == /foo/bar) > test_abspath 3 TPASS : Test string matches expected string > _abspath(/foo/../bar) => /bar == /bar) > test_abspath 4 TPASS : Test string matches expected string > _abspath(/foo/bar/../baz) => /foo/baz == /foo/baz) > test_abspath 5 TPASS : Test string matches expected string > _abspath(/foo/bar/../baz/) => /foo/baz == /foo/baz) > test_abspath 6 TPASS : Test string matches expected string > _abspath(/foo/../bar/) => /bar == /bar) > test_abspath 7 TPASS : Test string matches expected string > _abspath(/foo/../bar/..) => / == /) > test_abspath 8 TPASS : Test string matches expected string > _abspath(/foo/../bar/../) => / == /) > test_abspath 9 TPASS : Test string matches expected string > _abspath(/foo/bar/../baz) => /foo/baz == /foo/baz) > test_abspath 10 TPASS : Test string matches expected string > _abspath(/foo/./bar) => /foo/bar == /foo/bar) > test_abspath 11 TPASS : Test string matches expected string > _abspath(/./foo/./bar) => /foo/bar == /foo/bar) > test_abspath 12 TPASS : Test string matches expected string > _abspath(/foo//bar) => /foo/bar == /foo/bar) > test_abspath 13 TPASS : Test string matches expected string > _abspath(//foo/bar) => /foo/bar == /foo/bar) > test_abspath 14 TPASS : Test string matches expected string > _abspath(//////foo/bar) => /foo/bar == /foo/bar) > test_abspath 15 TPASS : Test string matches expected string > _abspath(/foo/////bar) => /foo/bar == /foo/bar) > test_abspath 16 TPASS : Test string matches expected string > _abspath(/a/b/c/.././) => /a/b == /a/b) > test_abspath 17 TPASS : Test string matches expected string > _abspath(/.foo) => /.foo == /.foo) > test_abspath 18 TPASS : Test string matches expected string > _abspath(./.foo) => /.foo == /.foo) > test_abspath 19 TPASS : Test string matches expected string > _abspath(/.foo/.bar) => /.foo/.bar == /.foo/.bar) > test_abspath 20 TPASS : Test string matches expected string > _abspath(./.foo/.bar) => /.foo/.bar == /.foo/.bar) > > Index: scripts/lib/file_functions.sh > =================================================================== > RCS file: scripts/lib/file_functions.sh > diff -N scripts/lib/file_functions.sh > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ scripts/lib/file_functions.sh 17 Jan 2010 06:18:33 -0000 > @@ -0,0 +1,50 @@ > +#!/bin/sh > +# > +# File functions utilized as part of abspath.sh, realpath.sh, etc. > +# > +# Copyright (C) 2010, Cisco Systems Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program; if not, write to the Free Software Foundation, Inc., > +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > +# > +# Garrett Cooper, January 2010 > +# > +# POSIX compliant bourne shell functions for performing make 3.81 > +# compliancy in 3.80 with a minimal set of external commands > +# [awk(1) // readlink(1) only required]. > +# > + > +# 1. Replace /+ with /. > +# 2. Replace a/b/../c with a/c > +# 3. Replace /./ with / > +# 4. Replace trailing /. with / > +# 5. Replace heading ./ with / > +_abspath() { > + echo "$@" | awk '{ > + while (gsub(/\/\//, "/")) { }; > + while (gsub(/\/[^\/]+\/\.\.\/?/, "/")) { }; > + while (gsub(/\/\.\//, "/")) { }; > + sub(/(\/\.)?\/$/, ""); > + sub(/^\.\//, "/") ; > + if ($0 == "") { > + print "/"; > + } else { > + print; > + } > +}' > +} > + > +_realpath() { > + readlink -f "$@" > +} > Index: scripts/tests/test_abspath.sh > =================================================================== > RCS file: scripts/tests/test_abspath.sh > diff -N scripts/tests/test_abspath.sh > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ scripts/tests/test_abspath.sh 17 Jan 2010 06:18:33 -0000 > @@ -0,0 +1,73 @@ > +#!/bin/sh > +# > +# Test the _abspath function, utilized as part of abspath.sh > +# > +# Copyright (C) 2010, Cisco Systems Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program; if not, write to the Free Software Foundation, Inc., > +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > +# > +# Garrett Cooper, January 2010 > +# > + > +set -- foo/bar:foo/bar \ > + /foo/bar:/foo/bar \ > + /foo/../bar:/bar \ > + /foo/bar/../baz:/foo/baz \ > + /foo/bar/../baz/:/foo/baz \ > + /foo/../bar/:/bar \ > + /foo/../bar/..:/ \ > + /foo/../bar/../:/ \ > + /foo/bar/../baz:/foo/baz \ > + /foo/./bar:/foo/bar \ > + /./foo/./bar:/foo/bar \ > + /foo//bar:/foo/bar \ > + //foo/bar:/foo/bar \ > + //////foo/bar:/foo/bar \ > + /foo/////bar:/foo/bar \ > + /a/b/c/.././:/a/b \ > + /.foo:/.foo \ > + ./.foo:/.foo \ > + /.foo/.bar:/.foo/.bar \ > + ./.foo/.bar:/.foo/.bar > + > +export TCID=test_abspath > +export TST_TOTAL=$# > +export TST_COUNT=1 > + > +. "${0%/*}/../lib/file_functions.sh" > + > +for i in "$@"; do > + > + test_string=${i%:*} > + expected_string=${i#*:} > + > + result=$(_abspath "$test_string") > + > + if [ "$result" = "$expected_string" ]; then > + result_s="matches expected string _abspath(${test_string}) => > $result == $expected_string)" > + result_v=TPASS > + else > + result_s="doesn't match expected string _abspath(${test_string}) => > $result != $expected_string)" > + result_v=TFAIL > + FAILED=1 > + fi > + > + tst_resm $result_v "Test string $result_s" > + > + : $(( TST_COUNT += 1 )) > + > +done > + > +exit ${FAILED:=0} > Index: scripts/abspath.sh > =================================================================== > RCS file: scripts/abspath.sh > diff -N scripts/abspath.sh > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ scripts/abspath.sh 17 Jan 2010 06:18:33 -0000 > @@ -0,0 +1,29 @@ > +#!/bin/sh > +# > +# make 3.81 $(abspath .. ) emulation layer > +# > +# Copyright (C) 2010, Cisco Systems Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program; if not, write to the Free Software Foundation, Inc., > +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > +# > +# Garrett Cooper, January 2010 > +# > + > +. "${0%/*}/lib/file_functions.sh" > + > +while [ $# -gt 0 ] ; do > + _abspath "$1" > + shift > +done > Index: scripts/realpath.sh > =================================================================== > RCS file: scripts/realpath.sh > diff -N scripts/realpath.sh > --- /dev/null 1 Jan 1970 00:00:00 -0000 > +++ scripts/realpath.sh 17 Jan 2010 06:18:33 -0000 > @@ -0,0 +1,29 @@ > +#!/bin/sh > +# > +# make 3.81 $(realpath .. ) emulation layer > +# > +# Copyright (C) 2010, Cisco Systems Inc. > +# > +# This program is free software; you can redistribute it and/or modify > +# it under the terms of the GNU General Public License as published by > +# the Free Software Foundation; either version 2 of the License, or > +# (at your option) any later version. > +# > +# This program is distributed in the hope that it will be useful, > +# but WITHOUT ANY WARRANTY; without even the implied warranty of > +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +# GNU General Public License for more details. > +# > +# You should have received a copy of the GNU General Public License along > +# with this program; if not, write to the Free Software Foundation, Inc., > +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. > +# > +# Garrett Cooper, January 2010 > +# > + > +. "${0%/*}/lib/file_functions.sh" > + > +while [ $# -gt 0 ] ; do > + _realpath "$1" > + shift > +done > It appears that GNU make 3.81 makes some interesting assumptions about some corner cases (`', `.', relative paths), where it does the following: 1. relative paths automatically are prefixed with $PWD. 2. `' and '.' automatically translate to $PWD. This diff takes that behavior into account and adds appropriate testcases to match the behavior: gcooper@optimus /scratch/ltp $ scripts/tests/test_abspath.sh test_abspath 1 TPASS : Test string matches expected string _abspath() => /scratch/ltp == /scratch/ltp) test_abspath 2 TPASS : Test string matches expected string _abspath(.) => /scratch/ltp == /scratch/ltp) test_abspath 3 TPASS : Test string matches expected string _abspath(foo/bar) => /scratch/ltp/foo/bar == /scratch/ltp/foo/bar) test_abspath 4 TPASS : Test string matches expected string _abspath(/foo/bar) => /foo/bar == /foo/bar) test_abspath 5 TPASS : Test string matches expected string _abspath(/foo/../bar) => /bar == /bar) test_abspath 6 TPASS : Test string matches expected string _abspath(/foo/bar/../baz) => /foo/baz == /foo/baz) test_abspath 7 TPASS : Test string matches expected string _abspath(/foo/bar/../baz/) => /foo/baz == /foo/baz) test_abspath 8 TPASS : Test string matches expected string _abspath(/foo/../bar/) => /bar == /bar) test_abspath 9 TPASS : Test string matches expected string _abspath(/foo/../bar/..) => / == /) test_abspath 10 TPASS : Test string matches expected string _abspath(/foo/../bar/../) => / == /) test_abspath 11 TPASS : Test string matches expected string _abspath(/foo/bar/../baz) => /foo/baz == /foo/baz) test_abspath 12 TPASS : Test string matches expected string _abspath(/foo/./bar) => /foo/bar == /foo/bar) test_abspath 13 TPASS : Test string matches expected string _abspath(/./foo/./bar) => /foo/bar == /foo/bar) test_abspath 14 TPASS : Test string matches expected string _abspath(/foo//bar) => /foo/bar == /foo/bar) test_abspath 15 TPASS : Test string matches expected string _abspath(//foo/bar) => /foo/bar == /foo/bar) test_abspath 16 TPASS : Test string matches expected string _abspath(//////foo/bar) => /foo/bar == /foo/bar) test_abspath 17 TPASS : Test string matches expected string _abspath(/foo/////bar) => /foo/bar == /foo/bar) test_abspath 18 TPASS : Test string matches expected string _abspath(/a/b/c/.././) => /a/b == /a/b) test_abspath 19 TPASS : Test string matches expected string _abspath(/.foo) => /.foo == /.foo) test_abspath 20 TPASS : Test string matches expected string _abspath(./.foo) => /.foo == /.foo) test_abspath 21 TPASS : Test string matches expected string _abspath(/.foo/.bar) => /.foo/.bar == /.foo/.bar) test_abspath 22 TPASS : Test string matches expected string _abspath(./.foo/.bar) => /.foo/.bar == /.foo/.bar) Unless there are some style or implementation issues with the code here, I'd say it's ready for commit. Signed-off-by: Garrett Cooper <yan...@gm...> Index: scripts/lib/file_functions.sh =================================================================== RCS file: scripts/lib/file_functions.sh diff -N scripts/lib/file_functions.sh --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scripts/lib/file_functions.sh 18 Jan 2010 01:15:32 -0000 @@ -0,0 +1,64 @@ +#!/bin/sh +# +# File functions utilized as part of abspath.sh, realpath.sh, etc. +# +# Copyright (C) 2010, Cisco Systems Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Garrett Cooper, January 2010 +# +# POSIX compliant bourne shell functions for performing make 3.81 +# compliancy in 3.80 with a minimal set of external commands +# [awk(1) // readlink(1) only required]. +# + +# 1. Strip all heading and leading space. +# 1. Replace /+ with /. +# 2. Replace a/b/../c with a/c +# 3. Replace /./ with / +# 4. Replace trailing /. with / +# 5. Replace heading ./ with / +_abspath() { + echo "$@" | awk -v PWD=$(pwd) '{ + sub(/^[[:space:]]+/, ""); sub(/[[:space:]]+$/, "") + if ($0 == "") { + print PWD + } else { + while (gsub(/\/\//, "/")) { }; + while (gsub(/\/[^\/]+\/\.\.\/?/, "/")) { }; + while (gsub(/\/\.\//, "/")) { }; + sub(/(\/\.)?\/$/, ""); + sub(/^\.\//, "/") ; + if ($0 == "") { + print "/" + } else { + if ($0 == ".") { + print PWD + } else { + if (!($0 ~ /^\//)) { + print PWD "/" $0 + } else { + print + } + } + } + } +}' +} + +_realpath() { + readlink -f "$@" +} Index: scripts/tests/test_abspath.sh =================================================================== RCS file: scripts/tests/test_abspath.sh diff -N scripts/tests/test_abspath.sh --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scripts/tests/test_abspath.sh 18 Jan 2010 01:15:32 -0000 @@ -0,0 +1,76 @@ +#!/bin/sh +# +# Test the _abspath function, utilized as part of abspath.sh +# +# Copyright (C) 2010, Cisco Systems Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Garrett Cooper, January 2010 +# + +set -- \ + :$PWD \ + .:$PWD \ + foo/bar:$PWD/foo/bar \ + /foo/bar:/foo/bar \ + /foo/../bar:/bar \ + /foo/bar/../baz:/foo/baz \ + /foo/bar/../baz/:/foo/baz \ + /foo/../bar/:/bar \ + /foo/../bar/..:/ \ + /foo/../bar/../:/ \ + /foo/bar/../baz:/foo/baz \ + /foo/./bar:/foo/bar \ + /./foo/./bar:/foo/bar \ + /foo//bar:/foo/bar \ + //foo/bar:/foo/bar \ + //////foo/bar:/foo/bar \ + /foo/////bar:/foo/bar \ + /a/b/c/.././:/a/b \ + /.foo:/.foo \ + ./.foo:/.foo \ + /.foo/.bar:/.foo/.bar \ + ./.foo/.bar:/.foo/.bar + +export TCID=test_abspath +export TST_TOTAL=$# +export TST_COUNT=1 + +. "${0%/*}/../lib/file_functions.sh" + +for i in "$@"; do + + test_string=${i%:*} + expected_string=${i#*:} + + result=$(_abspath "$test_string") + + if [ "$result" = "$expected_string" ]; then + result_s="matches expected string _abspath(${test_string}) => $result == $expected_string)" + result_v=TPASS + else + result_s="doesn't match expected string _abspath(${test_string}) => $result != $expected_string)" + result_v=TFAIL + FAILED=1 + fi + + tst_resm $result_v "Test string $result_s" + + : $(( TST_COUNT += 1 )) + +done + +exit ${FAILED:=0} Index: scripts/abspath.sh =================================================================== RCS file: scripts/abspath.sh diff -N scripts/abspath.sh --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scripts/abspath.sh 18 Jan 2010 01:15:32 -0000 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# make 3.81 $(abspath .. ) emulation layer +# +# Copyright (C) 2010, Cisco Systems Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Garrett Cooper, January 2010 +# + +. "${0%/*}/lib/file_functions.sh" + +while [ $# -gt 0 ] ; do + _abspath "$1" + shift +done Index: scripts/realpath.sh =================================================================== RCS file: scripts/realpath.sh diff -N scripts/realpath.sh --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ scripts/realpath.sh 18 Jan 2010 01:15:32 -0000 @@ -0,0 +1,29 @@ +#!/bin/sh +# +# make 3.81 $(realpath .. ) emulation layer +# +# Copyright (C) 2010, Cisco Systems Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Garrett Cooper, January 2010 +# + +. "${0%/*}/lib/file_functions.sh" + +while [ $# -gt 0 ] ; do + _realpath "$1" + shift +done |