Repository: cookiecutter/cookiecutter

Issue:
Add aliases for cookiecutters
Remembering the locations of cookiecutters can be a bit of a pain - even if it's just including the local path.

It would be useful to have an extra section in `cookiecutterrc` for aliases to cookiecutter locations. Something like:

```
aliases:
  python: https://github.com/audreyr/cookiecutter-pypackage
  django: https://github.com/marcofucci/cookiecutter-simple-django
  docs: ~/samples/templates/documentation
```

The code would simply need to translate an alias into a path before doing any of the existing processing.



Discussion:
Hmm, I can't add labels (is that a contributor-only feature of github?) but I'd suggest "enhancement" and "discussion" :-)

@pfmoore Can you email me?

In a similar vein, would there be any interest in building in aliases for a few of the most popular hosting sites, so you could do e.g. `cookiecutter gh:audreyr/cookiecutter-pypackage` instead of the full path?

@takluyver Seems like a reasonable idea. Built in ones would be, I guess, `gh` for github, `bb` for bitbucket. I can't think of any others. Allowing users to define their own seems like YAGNI, although it would be relatively easy to do. Something like:

```
aliases:
    gh: https://github.com/{}
    me: https://github.com/pfmoore/{}
```

(The presence of the `{}` indicates that there should be a suffix).

@pfmoore I think allowing users to define their own repo aliases would be really helpful, for what it's worth.  I have several privately-hosted repo sites (personal, work, various clients) that I use on a regular basis, and it would be nice to be able to use them without typing out the full url.

Am I crazy to think that this discussion and implementation could have "synergy" :scream: with #92?


Resolving patch:
diff --git a/cookiecutter/main.py b/cookiecutter/main.py
--- a/cookiecutter/main.py
+++ b/cookiecutter/main.py
@@ -25,6 +25,34 @@
 
 logger = logging.getLogger(__name__)
 
+builtin_abbreviations = {
+    'gh': 'https://github.com/{0}.git',
+    'bb': 'https://bitbucket.org/{0}',
+}
+
+def expand_abbreviations(input_dir, config_dict):
+    """
+    Expand abbreviations in a template name.
+
+    :param input_dir: The project template name.
+    :param config_dict: The user config, which will contain abbreviation
+        definitions.
+    """
+
+    abbreviations = builtin_abbreviations.copy()
+    abbreviations.update(config_dict.get('abbreviations', {}))
+
+    if input_dir in abbreviations:
+        return abbreviations[input_dir]
+
+    # Split on colon. If there is no colon, rest will be empty
+    # and prefix will be the whole input_dir
+    prefix, sep, rest = input_dir.partition(':')
+    if prefix in abbreviations:
+        return abbreviations[prefix].format(rest)
+
+    return input_dir
+
 
 def cookiecutter(input_dir, checkout=None, no_input=False):
     """
@@ -39,6 +67,8 @@ def cookiecutter(input_dir, checkout=None, no_input=False):
     # If no config file, sensible defaults from config.DEFAULT_CONFIG are used
     config_dict = get_user_config()
 
+    input_dir = expand_abbreviations(input_dir, config_dict)
+
     # TODO: find a better way to tell if it's a repo URL
     if "git@" in input_dir or "https://" in input_dir:
         repo_dir = clone(


Test patch:
diff --git a/tests/test_main.py b/tests/test_main.py
--- a/tests/test_main.py
+++ b/tests/test_main.py
@@ -95,6 +95,41 @@ def test_parse_cookiecutter_args_with_branch(self):
         self.assertEqual(args.checkout, 'develop')
 
 
+class TestAbbreviationExpansion(unittest.TestCase):
+
+    def test_abbreviation_expansion(self):
+        input_dir = main.expand_abbreviations('foo', {'abbreviations': {'foo': 'bar'}})
+        self.assertEqual(input_dir, 'bar')
+
+    def test_abbreviation_expansion_not_an_abbreviation(self):
+        input_dir = main.expand_abbreviations('baz', {'abbreviations': {'foo': 'bar'}})
+        self.assertEqual(input_dir, 'baz')
+
+    def test_abbreviation_expansion_prefix(self):
+        input_dir = main.expand_abbreviations('xx:a', {'abbreviations': {'xx': '<{0}>'}})
+        self.assertEqual(input_dir, '<a>')
+
+    def test_abbreviation_expansion_builtin(self):
+        input_dir = main.expand_abbreviations('gh:a', {})
+        self.assertEqual(input_dir, 'https://github.com/a.git')
+
+    def test_abbreviation_expansion_override_builtin(self):
+        input_dir = main.expand_abbreviations('gh:a', {'abbreviations': {'gh': '<{0}>'}})
+        self.assertEqual(input_dir, '<a>')
+
+    def test_abbreviation_expansion_prefix_ignores_suffix(self):
+        input_dir = main.expand_abbreviations('xx:a', {'abbreviations': {'xx': '<>'}})
+        self.assertEqual(input_dir, '<>')
+
+    def test_abbreviation_expansion_prefix_not_0_in_braces(self):
+        self.assertRaises(
+            IndexError,
+            main.expand_abbreviations,
+            'xx:a',
+            {'abbreviations': {'xx': '{1}'}}
+        )
+
+
 @unittest.skipIf(condition=no_network, reason='Needs a network connection to GitHub/Bitbucket.')
 class TestCookiecutterRepoArg(CookiecutterCleanSystemTestCase):