From f81f9ceb40db8b3dbb586e52a3939dd8a136502f Mon Sep 17 00:00:00 2001 From: Owen Waller Date: Mon, 22 Sep 2014 18:40:09 +0100 Subject: [PATCH] Fix: rewrite FileAndExt FileAndExt has now be completely rewritten and now works as may reasonably be expected. The test cases for: ReplaceExtension Filename FileAndExt now all pass. The problem was the way path.Base was being used. Firstly Base returns "." if the directory is empty, but it can also return "." for the current directory, or ".." for the parent directory, if these are the last elements in the path. Simply detecting the presence of a "." in the returned string and truncating before the "." does not therefore always result in a valid filename. Secondly, Base strips any trailing slashes making is more difficult to detect when the path does not end in a filename but in a directory name i.e. a no filename case. Not detecting this incorrectly results in the last directory name being returned as the filename. The code has been updated to take account of of both situations so that: 1) An empty string for both the filename and extension is returned if the path does not contain a filename (plus an optional extension). This includes both the empty path case, and the ends in a directory case. 2) If the path represents a filename with an extension then both the filename and the extension (minus any dots) are returned as non empty strings. 3) If the path represents a filename without an extension then filename will be returned as a non empty string (minus any dot) and the extension will be returned as an empty string. --- helpers/path.go | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/helpers/path.go b/helpers/path.go index 0425a5ae3..c994cce7c 100644 --- a/helpers/path.go +++ b/helpers/path.go @@ -158,16 +158,38 @@ func Filename(in string) (name string) { return } +// FileAndExt returns the filename and any extension of a file path as +// two separate strings. +// If path, in, contains a directory name ending in a slash then +// both name and ext will be empty strings. +// If the path, in, is either the current directory, the parent +// directory or the root directory, or an empty string, then both +// name and ext will be empty strings. +// If the path, in, represents the path of a file without an extension +// then name will be the name of the file and ext will be an empty string. +// If the path, in, represents a filename with an extension then +// then name will be the filename minus any extension - including the dot +// and ext will contain the extension - minus the dot. func FileAndExt(in string) (name string, ext string) { ext = path.Ext(in) - base := path.Base(in) + base := path.Base(in) // path.Base strips any trailing slash! - if strings.Contains(base, ".") { + // No file name cases. These are defined as: + // 1. any "in" path that ends in a os.PathSeparator i.e. "/" on linux + // 2. any "base" consisting of just an os.PathSeparator + // 3. any "base" consisting of just an empty string + // 4. any "base" consisting of just the current directory i.e. "." + // 5. any "base" consisting of just the parent directory i.e. ".." + if (strings.LastIndex(in, string(os.PathSeparator)) == len(in)-1) || base == "" || base == "." || base == ".." || base == string(os.PathListSeparator) { + name = "" // there is NO filename + } else if ext != "" { // there was an Extension + // return the filename minus the extension (and the ".") name = base[:strings.LastIndex(base, ".")] } else { - name = in + // no extension case so just return base, which willi + // be the filename + name = base } - return }