Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Support for external base projects. #34

Closed
wants to merge 5 commits into from

4 participants

Nolan Brubaker Noah Isaacson Luke Hatcher Brian Rosner
Nolan Brubaker

These commits add support for using git and hg pip editables, as well as plain directories to the setup_project -b option.

Luke Hatcher lukeman closed this March 13, 2012
Noah Isaacson

Can you give an example of a live project that can be installed in this manner?

I am trying to create a new project using the latest dev branch of pinax-project-account and cannot see how to do this from the https://github.com/pinax/pinax-project-account page

see http://stackoverflow.com/questions/10804923/how-can-i-install-external-pinax-projects for more

nrb replied May 31, 2012

Sorry, I can't; this pull request is actually deprecated in favor of a different implementation. I haven't been too involved in the project for a few months now, you may want to check on #pinax in IRC to see if they have made any progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
11  docs/starterprojects.txt
@@ -156,3 +156,14 @@ the Django templating language. It uses ``pinax.views.static_view`` mounted
156 156
 at ``/``. For example if you access ``/test.html`` it will render
157 157
 ``templates/test.html``. Directory paths, i.e., ``/a/``, will render
158 158
 ``/templates/a/index.html``.
  159
+
  160
+External Starter Projects
  161
+=========================
  162
+
  163
+The Pinax ``setup_project`` command can also use starter projects built by third parties. 
  164
+These can either be plain directory structures, or they may be a git/hg pip editable.
  165
+
  166
+To install a starter project from an external source, simply pass the file path or git/hg 
  167
+URL to the ``-b`` option::
  168
+
  169
+    pinax-admin setup_project -b git+git://github.com/user/project.git#egg=project my_new_project
100  pinax/core/management/commands/setup_project.py
@@ -5,8 +5,13 @@
5 5
 import re
6 6
 import shutil
7 7
 import sys
  8
+import urlparse
8 9
 
9 10
 import pip
  11
+from pip.index import PackageFinder
  12
+from pip.locations import build_prefix, src_prefix
  13
+from pip.req import InstallRequirement, RequirementSet
  14
+from pip.vcs import vcs
10 15
 
11 16
 try:
12 17
     from pip.exceptions import InstallationError
@@ -32,12 +37,12 @@ class Command(BaseCommand):
32 37
         optparse.make_option("-l", "--list-bases",
33 38
             dest = "list_bases",
34 39
             action = "store_true",
35  
-            help = "lists the starter projects (bases) that are available"
  40
+            help = "lists the bundled starter projects (bases) that are available"
36 41
         ),
37 42
         optparse.make_option("-b", "--base",
38 43
             dest = "base",
39 44
             default = "zero",
40  
-            help = "the starter project to use as a base (excluding _project, e.g., basic or social. see --list-projects)"
  45
+            help = "the starter project to use as a base (excluding _project, e.g., basic or social. see --list-projects for included starter projects).  Valid git/hg PIP editable strings and plain file paths are accepted, as well."
41 46
         ),
42 47
         optparse.make_option("--no-reqs",
43 48
             dest = "no_reqs",
@@ -113,15 +118,11 @@ def setup_project(self, destination, base, options):
113 118
         # allow repos and such)
114 119
         if base in [p.replace("_project", "") for p in self.project_list()]:
115 120
             project_name = "%s_project" % base
116  
-            source = os.path.join(PROJECTS_DIR, project_name)
  121
+            source = "file+file://%s" % os.path.join(PROJECTS_DIR, project_name)
117 122
         else:
118  
-            if not os.path.exists(base):
119  
-                raise CommandError(
120  
-                    "Project template does not exist the given "
121  
-                    "path: %s" % base
122  
-                )
123  
-            else:
124  
-                project_name = os.path.basename(base)
  123
+            project_name = user_project_name
  124
+            source = base
  125
+
125 126
         
126 127
         installer = ProjectInstaller(source, destination, project_name, user_project_name)
127 128
         installer.copy()
@@ -146,22 +147,85 @@ class ProjectInstaller(object):
146 147
     Provides the methods to install a project at a given destination
147 148
     """
148 149
     
149  
-    def __init__(self, source_dir, project_dir, project_name, user_project_name):
150  
-        self.source_dir = source_dir
151  
-        self.project_dir = project_dir
  150
+    @classmethod
  151
+    def clean_source(cls, source):
  152
+        if os.path.exists(source):
  153
+            kind, url = "file", source
  154
+        else:
  155
+            kind, url = source.split("+", 1)
  156
+            source = urlparse.urlparse(url)
  157
+        
  158
+        if kind not in ["file", "git", "hg"]:
  159
+            raise CommandError("project base is invalid")
  160
+        
  161
+        if kind == "file":
  162
+            source = os.path.abspath(source)
  163
+        
  164
+        return kind, source
  165
+    
  166
+    def __init__(self, source, project_dir, project_name, user_project_name):
  167
+        self.kind, self.source = self.clean_source(source)
  168
+        self.project_dir = os.path.join(os.getcwd(), project_dir)
152 169
         self.project_name = project_name
153 170
         self.user_project_name = user_project_name
  171
+        
  172
+        if self.kind in ["git", "hg"]:
  173
+            # Extract the name of the installed egg from the provided URL.
  174
+            self.egg_name = source.rsplit("#egg=", 1)[1]
  175
+    
  176
+    def parse_source(self, source):
  177
+        kind, url = source.split("+", 1)
  178
+        return kind, urlparse.urlparse(url)
154 179
     
155 180
     def generate_secret_key(self):
156 181
         chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)"
157 182
         return "".join([random.choice(chars) for i in xrange(50)])
158 183
     
159 184
     def copy(self):
160  
-        copytree(self.source_dir, self.project_dir,
161  
-            excluded_patterns=[
162  
-                ".svn", ".pyc", "dev.db"
163  
-            ]
164  
-        )
  185
+        if self.kind in ["git", "hg"]:
  186
+            # Let pip import version control information.
  187
+            pip.version_control()
  188
+            
  189
+            reqset = RequirementSet(
  190
+                build_dir=build_prefix,
  191
+                src_dir=src_prefix,
  192
+                download_dir=None
  193
+            )
  194
+            
  195
+            # Let pip do all the heavy lifting for VCS-based packages.
  196
+            req = InstallRequirement.from_editable(
  197
+                self.source.geturl(),
  198
+                default_vcs=self.kind
  199
+            )
  200
+            reqset.add_requirement(req)
  201
+            
  202
+            finder = PackageFinder(find_links=[], index_urls=[])
  203
+            
  204
+            reqset.prepare_files(finder)
  205
+            reqset.install(install_options=[], global_options=[])
  206
+            reqset.cleanup_files()
  207
+            
  208
+            # Try to build a path to the newly installed package.
  209
+            installed_path = os.path.join(src_prefix, self.egg_name, self.egg_name)
  210
+            
  211
+            # A bit of a hack, but most commonly package names replace dashes with underscores.
  212
+            if not os.path.exists(installed_path):
  213
+                package_name = self.egg_name.replace("-", "_")
  214
+                installed_path = os.path.join(src_prefix, self.egg_name, package_name)
  215
+            
  216
+            copytree(installed_path, self.project_dir,
  217
+                excluded_patterns=[
  218
+                    ".git", ".gitignore", ".hg", ".hgignore", ".pyc", "dev.db"
  219
+                ]
  220
+            )
  221
+        elif self.kind == "file":
  222
+            copytree(self.source, self.project_dir,
  223
+                excluded_patterns=[
  224
+                    ".svn", ".pyc", "dev.db"
  225
+                ]
  226
+            )
  227
+        else:
  228
+            raise Exception("unsupported kind")
165 229
     
166 230
     def fix_settings(self):
167 231
         # @@@ settings refactor
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.