Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
e84092f8
Commit
e84092f8
authored
May 12, 2015
by
Paul Morie
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add variable expansion and design doc
parent
d7834f50
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
383 additions
and
0 deletions
+383
-0
expansion.md
docs/design/expansion.md
+0
-0
expand.go
third_party/golang/expansion/expand.go
+98
-0
expand_test.go
third_party/golang/expansion/expand_test.go
+285
-0
No files found.
docs/design/expansion.md
0 → 100644
View file @
e84092f8
This diff is collapsed.
Click to expand it.
third_party/golang/expansion/expand.go
0 → 100644
View file @
e84092f8
package
expansion
const
(
operator
=
'$'
referenceOpener
=
'('
referenceCloser
=
')'
)
// syntaxWrap returns the input string wrapped the expansion syntax.
func
syntaxWrap
(
input
string
)
string
{
return
string
(
operator
)
+
string
(
referenceOpener
)
+
input
+
string
(
referenceCloser
)
}
// MappingFuncFor returns a mapping function for use with Expand that
// implements the expansion semantics defined in the expansion spec; it
// returns the input string wrapped in the expansion syntax if no mapping
// for the input is found.
func
MappingFuncFor
(
context
...
map
[
string
]
string
)
func
(
string
)
string
{
return
func
(
input
string
)
string
{
for
_
,
vars
:=
range
context
{
val
,
ok
:=
vars
[
input
]
if
ok
{
return
val
}
}
return
syntaxWrap
(
input
)
}
}
// Expand replaces variable references in the input string according to
// the expansion spec using the given mapping function to resolve the
// values of variables.
func
Expand
(
input
string
,
mapping
func
(
string
)
string
)
string
{
buf
:=
make
([]
byte
,
0
,
2
*
len
(
input
))
checkpoint
:=
0
for
cursor
:=
0
;
cursor
<
len
(
input
);
cursor
++
{
if
input
[
cursor
]
==
operator
&&
cursor
+
1
<
len
(
input
)
{
// Copy the portion of the input string since the last
// checkpoint into the buffer
buf
=
append
(
buf
,
input
[
checkpoint
:
cursor
]
...
)
// Attempt to read the variable name as defined by the
// syntax from the input string
read
,
isVar
,
advance
:=
tryReadVariableName
(
input
[
cursor
+
1
:
])
if
isVar
{
// We were able to read a variable name correctly;
// apply the mapping to the variable name and copy the
// bytes into the buffer
buf
=
append
(
buf
,
mapping
(
read
)
...
)
}
else
{
// Not a variable name; copy the read bytes into the buffer
buf
=
append
(
buf
,
read
...
)
}
// Advance the cursor in the input string to account for
// bytes consumed to read the variable name expression
cursor
+=
advance
// Advance the checkpoint in the input string
checkpoint
=
cursor
+
1
}
}
// Return the buffer and any remaining unwritten bytes in the
// input string.
return
string
(
buf
)
+
input
[
checkpoint
:
]
}
// tryReadVariableName attempts to read a variable name from the input
// string and returns the content read from the input, whether that content
// represents a variable name to perform mapping on, and the number of bytes
// consumed in the input string.
//
// The input string is assumed not to contain the initial operator.
func
tryReadVariableName
(
input
string
)
(
string
,
bool
,
int
)
{
switch
input
[
0
]
{
case
operator
:
// Escaped operator; return it.
return
input
[
0
:
1
],
false
,
1
case
referenceOpener
:
// Scan to expression closer
for
i
:=
1
;
i
<
len
(
input
);
i
++
{
if
input
[
i
]
==
referenceCloser
{
return
input
[
1
:
i
],
true
,
i
+
1
}
}
// Incomplete reference; return it.
return
string
(
operator
)
+
string
(
referenceOpener
),
false
,
1
default
:
// Not the beginning of an expression, ie, an operator
// that doesn't begin an expression. Return the operator
// and the first rune in the string.
return
(
string
(
operator
)
+
string
(
input
[
0
])),
false
,
1
}
}
third_party/golang/expansion/expand_test.go
0 → 100644
View file @
e84092f8
package
expansion
import
(
"testing"
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
)
func
TestMapReference
(
t
*
testing
.
T
)
{
envs
:=
[]
api
.
EnvVar
{
{
Name
:
"FOO"
,
Value
:
"bar"
,
},
{
Name
:
"ZOO"
,
Value
:
"$(FOO)-1"
,
},
{
Name
:
"BLU"
,
Value
:
"$(ZOO)-2"
,
},
}
declaredEnv
:=
map
[
string
]
string
{
"FOO"
:
"bar"
,
"ZOO"
:
"$(FOO)-1"
,
"BLU"
:
"$(ZOO)-2"
,
}
serviceEnv
:=
map
[
string
]
string
{}
mapping
:=
MappingFuncFor
(
declaredEnv
,
serviceEnv
)
for
_
,
env
:=
range
envs
{
declaredEnv
[
env
.
Name
]
=
Expand
(
env
.
Value
,
mapping
)
}
expectedEnv
:=
map
[
string
]
string
{
"FOO"
:
"bar"
,
"ZOO"
:
"bar-1"
,
"BLU"
:
"bar-1-2"
,
}
for
k
,
v
:=
range
expectedEnv
{
if
e
,
a
:=
v
,
declaredEnv
[
k
];
e
!=
a
{
t
.
Errorf
(
"Expected %v, got %v"
,
e
,
a
)
}
else
{
delete
(
declaredEnv
,
k
)
}
}
if
len
(
declaredEnv
)
!=
0
{
t
.
Errorf
(
"Unexpected keys in declared env: %v"
,
declaredEnv
)
}
}
func
TestMapping
(
t
*
testing
.
T
)
{
context
:=
map
[
string
]
string
{
"VAR_A"
:
"A"
,
"VAR_B"
:
"B"
,
"VAR_C"
:
"C"
,
"VAR_REF"
:
"$(VAR_A)"
,
"VAR_EMPTY"
:
""
,
}
mapping
:=
MappingFuncFor
(
context
)
doExpansionTest
(
t
,
mapping
)
}
func
TestMappingDual
(
t
*
testing
.
T
)
{
context
:=
map
[
string
]
string
{
"VAR_A"
:
"A"
,
"VAR_EMPTY"
:
""
,
}
context2
:=
map
[
string
]
string
{
"VAR_B"
:
"B"
,
"VAR_C"
:
"C"
,
"VAR_REF"
:
"$(VAR_A)"
,
}
mapping
:=
MappingFuncFor
(
context
,
context2
)
doExpansionTest
(
t
,
mapping
)
}
func
doExpansionTest
(
t
*
testing
.
T
,
mapping
func
(
string
)
string
)
{
cases
:=
[]
struct
{
name
string
input
string
expected
string
}{
{
name
:
"whole string"
,
input
:
"$(VAR_A)"
,
expected
:
"A"
,
},
{
name
:
"repeat"
,
input
:
"$(VAR_A)-$(VAR_A)"
,
expected
:
"A-A"
,
},
{
name
:
"beginning"
,
input
:
"$(VAR_A)-1"
,
expected
:
"A-1"
,
},
{
name
:
"middle"
,
input
:
"___$(VAR_B)___"
,
expected
:
"___B___"
,
},
{
name
:
"end"
,
input
:
"___$(VAR_C)"
,
expected
:
"___C"
,
},
{
name
:
"compound"
,
input
:
"$(VAR_A)_$(VAR_B)_$(VAR_C)"
,
expected
:
"A_B_C"
,
},
{
name
:
"escape & expand"
,
input
:
"$$(VAR_B)_$(VAR_A)"
,
expected
:
"$(VAR_B)_A"
,
},
{
name
:
"compound escape"
,
input
:
"$$(VAR_A)_$$(VAR_B)"
,
expected
:
"$(VAR_A)_$(VAR_B)"
,
},
{
name
:
"mixed in escapes"
,
input
:
"f000-$$VAR_A"
,
expected
:
"f000-$VAR_A"
,
},
{
name
:
"backslash escape ignored"
,
input
:
"foo
\\
$(VAR_C)bar"
,
expected
:
"foo
\\
Cbar"
,
},
{
name
:
"backslash escape ignored"
,
input
:
"foo
\\\\
$(VAR_C)bar"
,
expected
:
"foo
\\\\
Cbar"
,
},
{
name
:
"lots of backslashes"
,
input
:
"foo
\\\\\\\\
$(VAR_A)bar"
,
expected
:
"foo
\\\\\\\\
Abar"
,
},
{
name
:
"nested var references"
,
input
:
"$(VAR_A$(VAR_B))"
,
expected
:
"$(VAR_A$(VAR_B))"
,
},
{
name
:
"nested var references second type"
,
input
:
"$(VAR_A$(VAR_B)"
,
expected
:
"$(VAR_A$(VAR_B)"
,
},
{
name
:
"value is a reference"
,
input
:
"$(VAR_REF)"
,
expected
:
"$(VAR_A)"
,
},
{
name
:
"value is a reference x 2"
,
input
:
"%%$(VAR_REF)--$(VAR_REF)%%"
,
expected
:
"%%$(VAR_A)--$(VAR_A)%%"
,
},
{
name
:
"empty var"
,
input
:
"foo$(VAR_EMPTY)bar"
,
expected
:
"foobar"
,
},
{
name
:
"unterminated expression"
,
input
:
"foo$(VAR_Awhoops!"
,
expected
:
"foo$(VAR_Awhoops!"
,
},
{
name
:
"expression without operator"
,
input
:
"f00__(VAR_A)__"
,
expected
:
"f00__(VAR_A)__"
,
},
{
name
:
"shell special vars pass through"
,
input
:
"$?_boo_$!"
,
expected
:
"$?_boo_$!"
,
},
{
name
:
"bare operators are ignored"
,
input
:
"$VAR_A"
,
expected
:
"$VAR_A"
,
},
{
name
:
"undefined vars are passed through"
,
input
:
"$(VAR_DNE)"
,
expected
:
"$(VAR_DNE)"
,
},
{
name
:
"multiple (even) operators, var undefined"
,
input
:
"$$$$$$(BIG_MONEY)"
,
expected
:
"$$$(BIG_MONEY)"
,
},
{
name
:
"multiple (even) operators, var defined"
,
input
:
"$$$$$$(VAR_A)"
,
expected
:
"$$$(VAR_A)"
,
},
{
name
:
"multiple (odd) operators, var undefined"
,
input
:
"$$$$$$$(GOOD_ODDS)"
,
expected
:
"$$$$(GOOD_ODDS)"
,
},
{
name
:
"multiple (odd) operators, var defined"
,
input
:
"$$$$$$$(VAR_A)"
,
expected
:
"$$$A"
,
},
{
name
:
"missing open expression"
,
input
:
"$VAR_A)"
,
expected
:
"$VAR_A)"
,
},
{
name
:
"shell syntax ignored"
,
input
:
"${VAR_A}"
,
expected
:
"${VAR_A}"
,
},
{
name
:
"trailing incomplete expression not consumed"
,
input
:
"$(VAR_B)_______$(A"
,
expected
:
"B_______$(A"
,
},
{
name
:
"trailing incomplete expression, no content, is not consumed"
,
input
:
"$(VAR_C)_______$("
,
expected
:
"C_______$("
,
},
{
name
:
"operator at end of input string is preserved"
,
input
:
"$(VAR_A)foobarzab$"
,
expected
:
"Afoobarzab$"
,
},
{
name
:
"shell escaped incomplete expr"
,
input
:
"foo-
\\
$(VAR_A"
,
expected
:
"foo-
\\
$(VAR_A"
,
},
{
name
:
"lots of $( in middle"
,
input
:
"--$($($($($--"
,
expected
:
"--$($($($($--"
,
},
{
name
:
"lots of $( in beginning"
,
input
:
"$($($($($--foo$("
,
expected
:
"$($($($($--foo$("
,
},
{
name
:
"lots of $( at end"
,
input
:
"foo0--$($($($("
,
expected
:
"foo0--$($($($("
,
},
{
name
:
"escaped operators in variable names are not escaped"
,
input
:
"$(foo$$var)"
,
expected
:
"$(foo$$var)"
,
},
{
name
:
"newline not expanded"
,
input
:
"
\n
"
,
expected
:
"
\n
"
,
},
}
for
_
,
tc
:=
range
cases
{
expanded
:=
Expand
(
tc
.
input
,
mapping
)
if
e
,
a
:=
tc
.
expected
,
expanded
;
e
!=
a
{
t
.
Errorf
(
"%v: expected %q, got %q"
,
tc
.
name
,
e
,
a
)
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment