Repository: JonathonReinhart/scuba

Issue:
`!from_yml` can't handle keys containing '.' characters
Due to how the "key" is parsed at [config.py](https://github.com/JonathonReinhart/scuba/blob/0244c81ec482d3c60202028bc075621447bc3ad1/scuba/config.py#L65) '.' characters must be escaped or somehow encapsulated. 

Discussion:

Patch:
diff --git a/doc/yaml-reference.md b/doc/yaml-reference.md
index 6d066d3..920d210 100644
--- a/doc/yaml-reference.md
+++ b/doc/yaml-reference.md
@@ -250,6 +250,28 @@ aliases
       - !from_yaml .gitlab-ci.yml part2.script
 ```
 
+This example shows how to reference job names containing a `.` character.
+
+**`.gitlab-ci.yml`**
+```yaml
+image: gcc:5.1
+
+.part1:
+  script:
+    - make something
+.part2:
+  script:
+    - make something-else
+```
+
+**`scuba.yml`**
+```yaml
+image: !from_yaml .gitlab-ci.yml image
+
+aliases
+  build_part1: !from_yaml .gitlab-ci.yml "\\.part1.script"
+  build_part2: !from_yaml .gitlab-ci.yml "\\.part2.script"
+```
 
 
 [YAML]: http://yaml.org/
diff --git a/scuba/config.py b/scuba/config.py
index f78afc6..e662807 100644
--- a/scuba/config.py
+++ b/scuba/config.py
@@ -1,6 +1,7 @@
 from __future__ import print_function
 import os
 import yaml
+import re
 import shlex
 try:
     basestring
@@ -62,8 +63,9 @@ class Loader(yaml.SafeLoader):
         # Retrieve the key
         try:
             cur = doc
-            for k in key.split('.'):
-                cur = cur[k]
+            # Use a negative look-behind to split the key on non-escaped '.' characters
+            for k in re.split(r'(?<!\\)\.', key):
+                cur = cur[k.replace('\\.', '.')]  # Be sure to replace any escaped '.' characters with *just* the '.'
         except KeyError:
             raise yaml.YAMLError('Key "{}" not found in {}'.format(key, filename))
         return cur


Test patch:
diff --git a/tests/test_config.py b/tests/test_config.py
index 26ea655..4da2d2f 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -178,6 +178,19 @@ class TestConfig(TmpDirTestCase):
         config = scuba.config.load_config('.scuba.yml')
         assert_equals(config.image, 'debian:8.2')
 
+    def test_load_config_image_from_yaml_nested_keys_with_escaped_characters(self):
+        '''load_config loads a config using !from_yaml with nested keys containing escaped '.' characters'''
+        with open('.gitlab.yml', 'w') as f:
+            f.write('.its:\n')
+            f.write('  somewhere.down:\n')
+            f.write('    here: debian:8.2\n')
+
+        with open('.scuba.yml', 'w') as f:
+            f.write('image: !from_yaml .gitlab.yml "\\.its.somewhere\\.down.here"\n')
+
+        config = scuba.config.load_config('.scuba.yml')
+        assert_equals(config.image, 'debian:8.2')
+
     def test_load_config_image_from_yaml_nested_key_missing(self):
         '''load_config raises ConfigError when !from_yaml references nonexistant key'''
         with open('.gitlab.yml', 'w') as f: