tar: minor refactoring of populateTree and flatten

Cleaned up some dead code, and made populateTree not
take in a *tar.Streamer argument, as the ts argument was
only used to set an error. The function now returns
an error (if any). Also made flatten not have to take in
a *tar.Streamer argument as well.

Signed-off-by: Stephen Chung <schung@redhat.com>
This commit is contained in:
Stephen Chung 2016-07-31 21:49:32 -04:00
parent aa6d7c2c6e
commit 822f319224
1 changed files with 65 additions and 66 deletions

131
tar.go
View File

@ -67,11 +67,10 @@ func (ts *tarStream) readHeaders() {
for { for {
hdr, err := ts.tarReader.Next() hdr, err := ts.tarReader.Next()
if err != nil { if err != nil {
flatten(&root, ts) flatten(&root, &ts.creator, ts.keywords)
ts.pipeReader.CloseWithError(err) ts.pipeReader.CloseWithError(err)
return return
} }
// Because the content of the file may need to be read by several // Because the content of the file may need to be read by several
// KeywordFuncs, it needs to be an io.Seeker as well. So, just reading from // KeywordFuncs, it needs to be an io.Seeker as well. So, just reading from
// ts.tarReader is not enough. // ts.tarReader is not enough.
@ -117,10 +116,7 @@ func (ts *tarStream) readHeaders() {
if hdr.FileInfo().IsDir() && keyword == "size" { if hdr.FileInfo().IsDir() && keyword == "size" {
continue continue
} }
// TODO: handle hardlinks
if string(hdr.Typeflag) == string('1') {
// TODO: get number of hardlinks for a file
}
val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile) val, err := keyFunc(hdr.Name, hdr.FileInfo(), tmpFile)
if err != nil { if err != nil {
ts.setErr(err) ts.setErr(err)
@ -171,7 +167,10 @@ func (ts *tarStream) readHeaders() {
e.Set = &s e.Set = &s
} }
} }
populateTree(&root, &e, hdr, ts) err = populateTree(&root, &e, hdr)
if err != nil {
ts.setErr(err)
}
tmpFile.Close() tmpFile.Close()
os.Remove(tmpFile.Name()) os.Remove(tmpFile.Name())
} }
@ -186,16 +185,17 @@ const (
parentDir parentDir
) )
// populateTree creates a file tree hierarchy using an Entry's Parent and // populateTree creates a pseudo file tree hierarchy using an Entry's Parent and
// Children fields. When examining the Entry e to insert in the tree, we // Children fields. When examining the Entry e to insert in the tree, we
// determine if the path to that Entry exists yet. If it does, insert it in the // determine if the path to that Entry exists yet. If it does, insert it in the
// appropriate position in the tree. If not, create a path with "placeholder" // appropriate position in the tree. If not, create a path up until the Entry's
// directories, and then insert the Entry. populateTree does not consider // directory that it is contained in. Then, insert the Entry.
// symbolic links yet. // root: the "." Entry
func populateTree(root, e *Entry, hdr *tar.Header, ts *tarStream) { // e: the Entry we are looking to insert
// hdr: the tar header struct associated with e
func populateTree(root, e *Entry, hdr *tar.Header) error {
isDir := hdr.FileInfo().IsDir() isDir := hdr.FileInfo().IsDir()
wd := filepath.Clean(hdr.Name) wd := filepath.Clean(hdr.Name)
if !isDir { if !isDir {
// If entry is a file, we only want the directory it's in. // If entry is a file, we only want the directory it's in.
wd = filepath.Dir(wd) wd = filepath.Dir(wd)
@ -207,31 +207,24 @@ func populateTree(root, e *Entry, hdr *tar.Header, ts *tarStream) {
root.Children = append([]*Entry{e}, root.Children...) root.Children = append([]*Entry{e}, root.Children...)
e.Parent = root e.Parent = root
} }
return return nil
} }
dirNames := strings.Split(wd, "/") dirNames := strings.Split(wd, "/")
parent := root parent := root
for _, name := range dirNames[1:] { for _, name := range dirNames[1:] {
if node := parent.Descend(name); node == nil { encoded, err := Vis(name)
if err != nil {
return err
}
if node := parent.Descend(encoded); node == nil {
// Entry for directory doesn't exist in tree relative to root // Entry for directory doesn't exist in tree relative to root
var newEntry *Entry newEntry := Entry{
if isDir { Name: encoded,
newEntry = e Type: RelativeType,
} else { Parent: parent,
encodedName, err := Vis(name)
if err != nil {
ts.setErr(err)
return
}
newEntry = &Entry{
Name: encodedName,
Type: RelativeType,
}
} }
newEntry.Parent = parent parent.Children = append(parent.Children, &newEntry)
parent.Children = append(parent.Children, newEntry) parent = &newEntry
parent = newEntry
} else { } else {
// Entry for directory exists in tree, just keep going // Entry for directory exists in tree, just keep going
parent = node parent = node
@ -241,82 +234,88 @@ func populateTree(root, e *Entry, hdr *tar.Header, ts *tarStream) {
parent.Children = append([]*Entry{e}, parent.Children...) parent.Children = append([]*Entry{e}, parent.Children...)
e.Parent = parent e.Parent = parent
} else { } else {
commentpath, err := e.Path() // the "placeholder" directory already exists in the Entry "parent",
// so now we have to replace it's underlying data with that from e,
// as well as set the Parent field. Note that we don't set parent = e
// because parent is already in the pseudo tree, we just need to
// complete it's data.
e.Parent = parent.Parent
*parent = *e
commentpath, err := parent.Path()
if err != nil { if err != nil {
ts.setErr(err) return err
return
} }
commentEntry := Entry{ parent.Prev = &Entry{
Raw: "# " + commentpath, Raw: "# " + commentpath,
Type: CommentType, Type: CommentType,
} }
e.Prev = &commentEntry
} }
return nil
} }
// After constructing the tree from the tar stream, we want to "flatten" this // After constructing a pseudo file hierarchy tree, we want to "flatten" this
// tree by appending Entry's into ts.creator.DH.Entries in an appropriate // tree by putting the Entries into a slice with appropriate positioning.
// manner to simplify writing the output with ts.creator.DH.WriteTo
// root: the "head" of the sub-tree to flatten // root: the "head" of the sub-tree to flatten
// ts : tarStream to keep track of Entry's // creator: a dhCreator that helps with the '/set' keyword
func flatten(root *Entry, ts *tarStream) { // keywords: keywords specified by the user that should be evaluated
func flatten(root *Entry, creator *dhCreator, keywords []string) {
if root.Prev != nil { if root.Prev != nil {
// root.Prev != nil implies root is a directory // root.Prev != nil implies root is a directory
ts.creator.DH.Entries = append(ts.creator.DH.Entries, creator.DH.Entries = append(creator.DH.Entries,
Entry{ Entry{
Type: BlankType, Type: BlankType,
Pos: len(ts.creator.DH.Entries), Pos: len(creator.DH.Entries),
}) })
root.Prev.Pos = len(ts.creator.DH.Entries) root.Prev.Pos = len(creator.DH.Entries)
ts.creator.DH.Entries = append(ts.creator.DH.Entries, *root.Prev) creator.DH.Entries = append(creator.DH.Entries, *root.Prev)
// Check if we need a new set // Check if we need a new set
if ts.creator.curSet == nil { if creator.curSet == nil {
ts.creator.curSet = &Entry{ creator.curSet = &Entry{
Type: SpecialType, Type: SpecialType,
Name: "/set", Name: "/set",
Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), ts.keywords), Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), keywords),
Pos: len(ts.creator.DH.Entries), Pos: len(creator.DH.Entries),
} }
ts.creator.DH.Entries = append(ts.creator.DH.Entries, *ts.creator.curSet) creator.DH.Entries = append(creator.DH.Entries, *creator.curSet)
} else { } else {
needNewSet := false needNewSet := false
for _, k := range root.Set.Keywords { for _, k := range root.Set.Keywords {
if !inSlice(k, ts.creator.curSet.Keywords) { if !inSlice(k, creator.curSet.Keywords) {
needNewSet = true needNewSet = true
break break
} }
} }
if needNewSet { if needNewSet {
ts.creator.curSet = &Entry{ creator.curSet = &Entry{
Name: "/set", Name: "/set",
Type: SpecialType, Type: SpecialType,
Pos: len(ts.creator.DH.Entries), Pos: len(creator.DH.Entries),
Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), ts.keywords), Keywords: keywordSelector(append(tarDefaultSetKeywords, root.Set.Keywords...), keywords),
} }
ts.creator.DH.Entries = append(ts.creator.DH.Entries, *ts.creator.curSet) creator.DH.Entries = append(creator.DH.Entries, *creator.curSet)
} }
} }
} }
root.Set = ts.creator.curSet root.Set = creator.curSet
root.Keywords = setDifference(root.Keywords, ts.creator.curSet.Keywords) root.Keywords = setDifference(root.Keywords, creator.curSet.Keywords)
root.Pos = len(ts.creator.DH.Entries) root.Pos = len(creator.DH.Entries)
ts.creator.DH.Entries = append(ts.creator.DH.Entries, *root) creator.DH.Entries = append(creator.DH.Entries, *root)
for _, c := range root.Children { for _, c := range root.Children {
flatten(c, ts) flatten(c, creator, keywords)
} }
if root.Prev != nil { if root.Prev != nil {
// Show a comment when stepping out // Show a comment when stepping out
root.Prev.Pos = len(ts.creator.DH.Entries) root.Prev.Pos = len(creator.DH.Entries)
ts.creator.DH.Entries = append(ts.creator.DH.Entries, *root.Prev) creator.DH.Entries = append(creator.DH.Entries, *root.Prev)
dotEntry := Entry{ dotEntry := Entry{
Type: DotDotType, Type: DotDotType,
Name: "..", Name: "..",
Pos: len(ts.creator.DH.Entries), Pos: len(creator.DH.Entries),
} }
ts.creator.DH.Entries = append(ts.creator.DH.Entries, dotEntry) creator.DH.Entries = append(creator.DH.Entries, dotEntry)
} }
} }
@ -332,7 +331,7 @@ func filter(root *Entry, p func(*Entry) bool) []Entry {
} }
if p(c) { if p(c) {
if c.Prev == nil { if c.Prev == nil {
// prepend directories // prepend files
validEntrys = append([]Entry{*c}, validEntrys...) validEntrys = append([]Entry{*c}, validEntrys...)
} else { } else {
validEntrys = append(validEntrys, *c) validEntrys = append(validEntrys, *c)