Add line information in the parsed Dockerfile.
| ... | ... |
@@ -30,6 +30,8 @@ type Node struct {
|
| 30 | 30 |
Attributes map[string]bool // special attributes for this node |
| 31 | 31 |
Original string // original line used before parsing |
| 32 | 32 |
Flags []string // only top Node should have this set |
| 33 |
+ StartLine int // the line in the original dockerfile where the node begins |
|
| 34 |
+ EndLine int // the line in the original dockerfile where the node ends |
|
| 33 | 35 |
} |
| 34 | 36 |
|
| 35 | 37 |
var ( |
| ... | ... |
@@ -101,19 +103,24 @@ func parseLine(line string) (string, *Node, error) {
|
| 101 | 101 |
// Parse is the main parse routine. |
| 102 | 102 |
// It handles an io.ReadWriteCloser and returns the root of the AST. |
| 103 | 103 |
func Parse(rwc io.Reader) (*Node, error) {
|
| 104 |
+ currentLine := 0 |
|
| 104 | 105 |
root := &Node{}
|
| 106 |
+ root.StartLine = -1 |
|
| 105 | 107 |
scanner := bufio.NewScanner(rwc) |
| 106 | 108 |
|
| 107 | 109 |
for scanner.Scan() {
|
| 108 | 110 |
scannedLine := strings.TrimLeftFunc(scanner.Text(), unicode.IsSpace) |
| 111 |
+ currentLine++ |
|
| 109 | 112 |
line, child, err := parseLine(scannedLine) |
| 110 | 113 |
if err != nil {
|
| 111 | 114 |
return nil, err |
| 112 | 115 |
} |
| 116 |
+ startLine := currentLine |
|
| 113 | 117 |
|
| 114 | 118 |
if line != "" && child == nil {
|
| 115 | 119 |
for scanner.Scan() {
|
| 116 | 120 |
newline := scanner.Text() |
| 121 |
+ currentLine++ |
|
| 117 | 122 |
|
| 118 | 123 |
if stripComments(strings.TrimSpace(newline)) == "" {
|
| 119 | 124 |
continue |
| ... | ... |
@@ -137,6 +144,15 @@ func Parse(rwc io.Reader) (*Node, error) {
|
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 | 139 |
if child != nil {
|
| 140 |
+ // Update the line information for the current child. |
|
| 141 |
+ child.StartLine = startLine |
|
| 142 |
+ child.EndLine = currentLine |
|
| 143 |
+ // Update the line information for the root. The starting line of the root is always the |
|
| 144 |
+ // starting line of the first child and the ending line is the ending line of the last child. |
|
| 145 |
+ if root.StartLine < 0 {
|
|
| 146 |
+ root.StartLine = currentLine |
|
| 147 |
+ } |
|
| 148 |
+ root.EndLine = currentLine |
|
| 140 | 149 |
root.Children = append(root.Children, child) |
| 141 | 150 |
} |
| 142 | 151 |
} |
| ... | ... |
@@ -12,6 +12,7 @@ import ( |
| 12 | 12 |
|
| 13 | 13 |
const testDir = "testfiles" |
| 14 | 14 |
const negativeTestDir = "testfiles-negative" |
| 15 |
+const testFileLineInfo = "testfile-line/Dockerfile" |
|
| 15 | 16 |
|
| 16 | 17 |
func getDirs(t *testing.T, dir string) []string {
|
| 17 | 18 |
f, err := os.Open(dir) |
| ... | ... |
@@ -117,3 +118,37 @@ func TestParseWords(t *testing.T) {
|
| 117 | 117 |
} |
| 118 | 118 |
} |
| 119 | 119 |
} |
| 120 |
+ |
|
| 121 |
+func TestLineInformation(t *testing.T) {
|
|
| 122 |
+ df, err := os.Open(testFileLineInfo) |
|
| 123 |
+ if err != nil {
|
|
| 124 |
+ t.Fatalf("Dockerfile missing for %s: %v", testFileLineInfo, err)
|
|
| 125 |
+ } |
|
| 126 |
+ defer df.Close() |
|
| 127 |
+ |
|
| 128 |
+ ast, err := Parse(df) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ t.Fatalf("Error parsing dockerfile %s: %v", testFileLineInfo, err)
|
|
| 131 |
+ } |
|
| 132 |
+ |
|
| 133 |
+ if ast.StartLine != 4 || ast.EndLine != 30 {
|
|
| 134 |
+ fmt.Fprintf(os.Stderr, "Wrong root line information: expected(%d-%d), actual(%d-%d)\n", 4, 30, ast.StartLine, ast.EndLine) |
|
| 135 |
+ t.Fatalf("Root line information doesn't match result.")
|
|
| 136 |
+ } |
|
| 137 |
+ if len(ast.Children) != 3 {
|
|
| 138 |
+ fmt.Fprintf(os.Stderr, "Wrong number of child: expected(%d), actual(%d)\n", 3, len(ast.Children)) |
|
| 139 |
+ t.Fatalf("Root line information doesn't match result.")
|
|
| 140 |
+ } |
|
| 141 |
+ expected := [][]int{
|
|
| 142 |
+ {4, 4},
|
|
| 143 |
+ {10, 11},
|
|
| 144 |
+ {16, 30},
|
|
| 145 |
+ } |
|
| 146 |
+ for i, child := range ast.Children {
|
|
| 147 |
+ if child.StartLine != expected[i][0] || child.EndLine != expected[i][1] {
|
|
| 148 |
+ fmt.Fprintf(os.Stderr, "Wrong line information for child %d: expected(%d-%d), actual(%d-%d)\n", |
|
| 149 |
+ i, expected[i][0], expected[i][1], child.StartLine, child.EndLine) |
|
| 150 |
+ t.Fatalf("Root line information doesn't match result.")
|
|
| 151 |
+ } |
|
| 152 |
+ } |
|
| 153 |
+} |
| 120 | 154 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,34 @@ |
| 0 |
+ |
|
| 1 |
+ |
|
| 2 |
+ |
|
| 3 |
+FROM brimstone/ubuntu:14.04 |
|
| 4 |
+ |
|
| 5 |
+ |
|
| 6 |
+# TORUN -v /var/run/docker.sock:/var/run/docker.sock |
|
| 7 |
+ |
|
| 8 |
+ |
|
| 9 |
+ENV GOPATH \ |
|
| 10 |
+/go |
|
| 11 |
+ |
|
| 12 |
+ |
|
| 13 |
+ |
|
| 14 |
+# Install the packages we need, clean up after them and us |
|
| 15 |
+RUN apt-get update \ |
|
| 16 |
+ && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.clean \
|
|
| 17 |
+ |
|
| 18 |
+ |
|
| 19 |
+ && apt-get install -y --no-install-recommends git golang ca-certificates \ |
|
| 20 |
+ && apt-get clean \ |
|
| 21 |
+ && rm -rf /var/lib/apt/lists \ |
|
| 22 |
+ |
|
| 23 |
+ && go get -v github.com/brimstone/consuldock \ |
|
| 24 |
+ && mv $GOPATH/bin/consuldock /usr/local/bin/consuldock \ |
|
| 25 |
+ |
|
| 26 |
+ && dpkg -l | awk '/^ii/ {print $2}' > /tmp/dpkg.dirty \
|
|
| 27 |
+ && apt-get remove --purge -y $(diff /tmp/dpkg.clean /tmp/dpkg.dirty | awk '/^>/ {print $2}') \
|
|
| 28 |
+ && rm /tmp/dpkg.* \ |
|
| 29 |
+ && rm -rf $GOPATH |
|
| 30 |
+ |
|
| 31 |
+ |
|
| 32 |
+ |
|
| 33 |
+ |