Hi Tim, Thanks for plugging your way through this! A few tiny comments below. I look forward to when we can collapse the CVS stuff into a URL somehow or other as well, but this is a good start :-) Cheers, mwh > === modified file 'lib/lp/code/browser/codeimport.py' > --- lib/lp/code/browser/codeimport.py 2009-12-08 02:32:03 +0000 > +++ lib/lp/code/browser/codeimport.py 2010-01-11 23:55:03 +0000 > @@ -15,7 +15,6 @@ > 'CodeImportView', > ] > > -from cgi import escape > > from BeautifulSoup import BeautifulSoup > from zope.app.form import CustomWidgetFactory > @@ -24,16 +23,16 @@ > from zope.component import getUtility > from zope.formlib import form > from zope.interface import Interface > -from zope.schema import Choice, TextLine > +from zope.schema import Choice > > from canonical.cachedproperty import cachedproperty > from canonical.launchpad import _ > +from canonical.launchpad.fields import URIField > from canonical.launchpad.interfaces.launchpad import ILaunchpadCelebrities > from lp.code.enums import ( > BranchSubscriptionDiffSize, BranchSubscriptionNotificationLevel, > CodeImportReviewStatus, CodeReviewNotificationLevel, > RevisionControlSystems) > -from lp.code.interfaces.branch import branch_name_validator > from lp.code.interfaces.branchnamespace import ( > get_branch_namespace, IBranchNamespacePolicy) > from lp.code.interfaces.codeimport import ( > @@ -128,8 +127,7 @@ > > custom_widget('cvs_root', StrippedTextWidget, displayWidth=50) > custom_widget('cvs_module', StrippedTextWidget, displayWidth=20) > - custom_widget('svn_branch_url', URIWidget, displayWidth=50) > - custom_widget('git_repo_url', URIWidget, displayWidth=50) > + custom_widget('url', URIWidget, displayWidth=50) > > @cachedproperty > def _super_user(self): > @@ -173,56 +171,73 @@ > canonical_url(code_import.branch), > code_import.branch.unique_name)) > > - def _validateSVN(self, svn_branch_url, existing_import=None): > - """If the user has specified a subversion url, we need > - to make sure that there isn't already an import with > - that url.""" > - if svn_branch_url is None: > + def _validateURL(self, url, existing_import=None, field_name='url'): > + """If the user has specified a url, we need to make sure that there > + isn't already an import with that url.""" > + if url is None: > self.setSecondaryFieldError( > - 'svn_branch_url', 'Enter the URL of a Subversion branch.') > + field_name, 'Enter the URL of a foreign VCS branch.') > else: > - code_import = getUtility(ICodeImportSet).getBySVNDetails( > - svn_branch_url) > + code_import = getUtility(ICodeImportSet).getByURL(url) > if (code_import is not None and > code_import != existing_import): > self.setFieldError( > - 'svn_branch_url', > + field_name, > structured(""" > - This Subversion branch URL is already specified for > + This foreign branch URL is already specified for > the imported branch %s.""", > canonical_url(code_import.branch), > code_import.branch.unique_name)) > > - def _validateGit(self, git_repo_url, existing_import=None): > - """If the user has specified a git repo url, we need > - to make sure that there isn't already an import with > - that url.""" > - if git_repo_url is None: > - self.setSecondaryFieldError( > - 'git_repo_url', 'Enter the URL of a Git repo.') > - else: > - code_import = getUtility(ICodeImportSet).getByGitDetails( > - git_repo_url) > - if (code_import is not None and > - code_import != existing_import): > - self.setFieldError( > - 'git_repo_url', > - structured(""" > - This Git repository URL is already specified for > - the imported branch %s.""", > - escape(canonical_url(code_import.branch)), > - escape(code_import.branch.unique_name))) > + > + > +class NewCodeImportForm(Interface): > + """The fields presented on the form for editing a code import.""" > + > + use_template( > + ICodeImport, > + ['product', 'rcs_type', 'cvs_root', 'cvs_module']) > + > + svn_branch_url = URIField( > + title=_("Branch URL"), required=False, > + description=_( > + "The URL of a Subversion branch, starting with svn:// or" > + " http(s)://. Only trunk branches are imported."), > + allowed_schemes=["http", "https", "svn"], > + allow_userinfo=False, > + allow_port=True, > + allow_query=False, > + allow_fragment=False, > + trailing_slash=False) > + > + git_repo_url = URIField( > + title=_("Repo URL"), required=False, > + description=_( > + "The URL of the git repository. The MASTER branch will be " > + "imported."), > + allowed_schemes=["git"], > + allow_userinfo=False, # Only anonymous access is supported. > + allow_port=True, > + allow_query=False, # Query makes no sense in Subversion. It's not your fault at all but "Query makes no sense in Subversion." makes no sense here. > + allow_fragment=False, > + trailing_slash=False) > + > + branch_name = copy_field( > + IBranch['name'], > + __name__='branch_name', > + title=_('Branch Name'), > + description=_( > + "This will be used in the branch URL to identify the " > + "imported branch. Examples: main, trunk."), > + ) > > > class CodeImportNewView(CodeImportBaseView): > """The view to request a new code import.""" > > + schema = NewCodeImportForm > for_input = True > label = 'Request a code import' > - field_names = [ > - 'product', 'rcs_type', 'svn_branch_url', 'cvs_root', 'cvs_module', > - 'git_repo_url', > - ] > > custom_widget('rcs_type', LaunchpadRadioWidget) > > @@ -236,19 +251,6 @@ > """Cancel should take the user back to the root site.""" > return '/' > > - def setUpFields(self): > - CodeImportBaseView.setUpFields(self) > - # Add in the field for the branch name. > - name_field = form.Fields( > - TextLine( > - __name__='branch_name', > - title=_('Branch Name'), required=True, description=_( > - "This will be used in the branch URL to identify the " > - "imported branch. Examples: main, trunk."), > - constraint=branch_name_validator), > - render_context=self.render_context) > - self.form_fields = self.form_fields + name_field > - > def setUpWidgets(self): > CodeImportBaseView.setUpWidgets(self) > > @@ -268,18 +270,31 @@ > self.rcs_type_git = str(git_button) > self.rcs_type_emptymarker = str(empty_marker) > > + def _getImportLocation(self, data): > + """Return the import location based on type.""" > + rcs_type = data['rcs_type'] > + if rcs_type == RevisionControlSystems.CVS: > + return data.get('cvs_root'), data.get('cvs_module'), None > + elif rcs_type == RevisionControlSystems.BZR_SVN: > + return None, None, data.get('svn_branch_url') > + elif rcs_type == RevisionControlSystems.GIT: > + return None, None, data.get('git_repo_url') > + else: > + raise AssertionError( > + 'Unexpected revision control type %r.' % rcs_type) > + > def _create_import(self, data, status): > """Create the code import.""" > + cvs_root, cvs_module, url = self._getImportLocation(data) > return getUtility(ICodeImportSet).new( > registrant=self.user, > product=data['product'], > branch_name=data['branch_name'], > rcs_type=data['rcs_type'], > - svn_branch_url=data['svn_branch_url'], > - cvs_root=data['cvs_root'], > - cvs_module=data['cvs_module'], > - review_status=status, > - git_repo_url=data['git_repo_url']) > + url=url, > + cvs_root=cvs_root, > + cvs_module=cvs_module, > + review_status=status) > > def _setBranchExists(self, existing_branch): > """Set a field error indicating that the branch already exists.""" > @@ -357,19 +372,13 @@ > # Make sure fields for unselected revision control systems > # are blanked out: > if rcs_type == RevisionControlSystems.CVS: > - data['svn_branch_url'] = None > - data['git_repo_url'] = None > self._validateCVS(data.get('cvs_root'), data.get('cvs_module')) > elif rcs_type == RevisionControlSystems.BZR_SVN: > - data['cvs_root'] = None > - data['cvs_module'] = None > - data['git_repo_url'] = None > - self._validateSVN(data.get('svn_branch_url')) > + self._validateURL( > + data.get('svn_branch_url'), field_name='svn_branch_url') > elif rcs_type == RevisionControlSystems.GIT: > - data['cvs_root'] = None > - data['cvs_module'] = None > - data['svn_branch_url'] = None > - self._validateGit(data.get('git_repo_url')) > + self._validateURL( > + data.get('git_repo_url'), field_name='git_repo_url') > else: > raise AssertionError( > 'Unexpected revision control type %r.' % rcs_type) > @@ -380,7 +389,7 @@ > > use_template( > ICodeImport, > - ['svn_branch_url', 'cvs_root', 'cvs_module', 'git_repo_url']) > + ['url', 'cvs_root', 'cvs_module']) > whiteboard = copy_field(IBranch['whiteboard']) > > > @@ -457,15 +466,12 @@ > # If the import is a Subversion import, then omit the CVS > # fields, and vice versa. > if self.code_import.rcs_type == RevisionControlSystems.CVS: > - self.form_fields = self.form_fields.omit( > - 'svn_branch_url', 'git_repo_url') > + self.form_fields = self.form_fields.omit('url') > elif self.code_import.rcs_type in (RevisionControlSystems.SVN, > - RevisionControlSystems.BZR_SVN): > - self.form_fields = self.form_fields.omit( > - 'cvs_root', 'cvs_module', 'git_repo_url') > - elif self.code_import.rcs_type == RevisionControlSystems.GIT: > - self.form_fields = self.form_fields.omit( > - 'cvs_root', 'cvs_module', 'svn_branch_url') > + RevisionControlSystems.BZR_SVN, > + RevisionControlSystems.GIT): > + self.form_fields = self.form_fields.omit( > + 'cvs_root', 'cvs_module') > else: > raise AssertionError('Unknown rcs_type for code import.') > > @@ -496,12 +502,9 @@ > data.get('cvs_root'), data.get('cvs_module'), > self.code_import) > elif self.code_import.rcs_type in (RevisionControlSystems.SVN, > - RevisionControlSystems.BZR_SVN): > - self._validateSVN( > - data.get('svn_branch_url'), self.code_import) > - elif self.code_import.rcs_type == RevisionControlSystems.GIT: > - self._validateGit( > - data.get('git_repo_url'), self.code_import) > + RevisionControlSystems.BZR_SVN, > + RevisionControlSystems.GIT): > + self._validateURL(data.get('url'), self.code_import) > else: > raise AssertionError('Unknown rcs_type for code import.') > > === modified file 'lib/lp/code/doc/codeimport-event.txt' > --- lib/lp/code/doc/codeimport-event.txt 2009-07-01 13:16:44 +0000 > +++ lib/lp/code/doc/codeimport-event.txt 2010-01-11 23:55:03 +0000 > @@ -108,9 +108,8 @@ > First we create a Subversion import. > > >>> from lp.code.enums import RevisionControlSystems > - >>> svn_url = 'svn://svn.example.com/trunk' > - >>> svn_import = new_code_import('svn-trunk', > - ... rcs_type=RevisionControlSystems.SVN, svn_branch_url=svn_url) You can delete new_code_import entirely now. > + >>> svn_import = factory.makeCodeImport( > + ... svn_branch_url='svn://svn.example.com/trunk') > > CodeImportSet.newCreate creates an event from the new CodeImport object > and the person that created it. Here, the creator is the nopriv user. > @@ -131,11 +130,11 @@ > > >>> print_items(svn_create_event) > CODE_IMPORT > - OWNER u'52' > + OWNER ... > REVIEW_STATUS u'NEW' > ASSIGNEE None > UPDATE_INTERVAL None > - SVN_BRANCH_URL u'svn://svn.example.com/trunk' > + URL u'svn://svn.example.com/trunk' > > The database IDs of the CodeImport is also recorded. It is useful to > collate events associated with deleted CodeImport objects. > @@ -149,14 +148,13 @@ > import source. For a CVS import, CVS details are recorded instead of the > Subversion URL. > > - >>> cvs_import = new_code_import('cvs-main', > - ... rcs_type=RevisionControlSystems.CVS, > + >>> cvs_import = factory.makeCodeImport( > ... cvs_root=':pserver: