def process_rspecs( self ): # # Look for RSpecs at the root of the view. Multiple RSpecs are # prohibited unless one of them ends up importing all of the others # (directly or indirectly). # # Collect all rspecs rspec_path_list = list() root_files = os.listdir( self.localPath ) rspec = None for f in root_files: root, ext = os.path.splitext( f ) if ext.lower() == '.rspec': rspec_path = os.path.join(self.getRoot(), f ) if rspec == None: rspec = RSpecFile( rspec_path, parent=None, view=self, wipe_cache=True) else: userErrorExit("Only one rspec is allowed at the root of the view.") if rspec == None: userErrorExit("No RSpec found in view") infoMessage("Using RSpec: '%s'"%(rspec.getFilename()), 2) self.setRSpec( rspec )
def getURLFromWorkingCopy( self, lc_path ): if not os.path.exists(lc_path): userErrorExit("Given path to local copy '%s' is invalid"%(lc_path)) entry = self.client.info( lc_path ) #strip the %20-quotations from the url return urllib.unquote( entry['url'] ) if entry != None else None
def createRepoFromRCS( rcs, id, path, href, rev ): rcs = rcs.lower() if rcs != None else None if rcs == 'svn': return CTXRepositorySVN( id, path, href, rev ) elif rcs == None or rcs =='': return CTXRepositoryFS( id, path, href, rev ) else: userErrorExit("Unsupported RCS for repository '%s'"%(id))
def process_rspecs( self ): # # Look for RSpecs at the root of the view. Multiple RSpecs are # prohibited unless one of them ends up importing all of the others # (directly or indirectly). # # Collect all rspecs rspec_path_list = list() root_files = os.listdir( self.localPath ) for f in root_files: root, ext = os.path.splitext( f ) if ext.lower() == '.rspec': rspec_path_list.append( os.path.join(self.getRoot(), f ) ) if len(rspec_path_list) != 0: infoMessage("RSpecs detected in view: \n %s"%("\n ".join(rspec_path_list)), 2) # Determine the import relationship between the RSpecs if len(rspec_path_list): # candidate_rspecs = list() for rspec_path in rspec_path_list: rspec = RSpecFile( rspec_path, parent=None, view=self ) remainder = False for potential_import in rspec_path_list: if potential_import == rspec_path: continue # skip checking if we import ourselves if potential_import not in rspec.getImportPaths( recursive=True ): remainder = True break # we found an RSpec not imported so move on to the next one # remainder is False if all other RSpecs could be found in the # import tree of 'rspec', or if 'rspec' is the only one present # in the view. if remainder == False: candidate_rspecs.append( rspec ) # We should have exactly ONE candidate rspec. If we have zero candidates, it # means no single rspec imports all the others. # If we have multiple candidates, it means more than one rspec imports all # the others. Both these cases are terminal errors since we have no logic # way of selecting one of the candidates. if len(candidate_rspecs) != 1: userErrorExit("RSpec selection is ambiguous. Only one RSpec is allowed in a view. If multiple RSpecs exist, at least one of them must directly or indirectly import the others") else: infoMessage("Using RSpec: '%s'"%(candidate_rspecs[0].getFilename()), 2) self.setRSpec( candidate_rspecs[0] ) else: infoMessage("No RSpec found in view", 2)
def getRevisionFromWorkingCopy( self, lc_path ): if not os.path.exists(lc_path): userErrorExit("Given path to local copy '%s' is invalid"%(lc_path)) entry = self.client.info( lc_path ) if entry.revision.kind == pysvn.opt_revision_kind.head: return 'HEAD' elif entry.revision.kind == pysvn.opt_revision_kind.number: return entry.revision.number else: ctxAssert( False, "Unhandled pysvn revision kind" )
def locate_git(): warn_hardcoded_git_path = False for git_cand in ['git', 'git.cmd', 'git.exe', 'git.bat']: for path in os.environ["PATH"].split(os.pathsep): if os.path.exists(os.path.join( path, git_cand)) and os.access( os.path.join( path, git_cand), os.X_OK): return git_cand for git_cand in ['git', 'git.cmd', 'git.exe', 'git.bat']: for path in ['C:\\Program Files\\Git\cmd', 'C:\\Program Files (x86)\\Git\\cmd', '/usr/bin', '/usr/local/bin']: if os.path.exists(os.path.join( path, git_cand)) and os.access( os.path.join( path, git_cand), os.X_OK): #warningMessage("Falling back to hardcoded git path") return os.path.join(path, git_cand) userErrorExit("Git cannot be found in your PATH. Please re-install Git and make sure the git.cmd, git.exe or git binary can be found in your PATH")
def isWorkingCopy( self, local_path ): try: entry = self.client.info( local_path ) except pysvn.ClientError, e: for message, code in e.args[1]: if code in [ERR_NOT_A_WORKING_COPY, ERR_INVALID_ARGUMENT]: return False elif code == ERR_UNSUPPORTED_WORKING_COPY_FORMAT: userErrorExit("Unsupported working copy format in '%s'\n \ Looks like the working copy was accessed using an incomptatible version of a svn client\n. \ PySvn currently uses svn version %s. "%(local_path, pysvn.svn_version) ) else: ctxAssert( False, "Unhandled pysvn exception: (%d) %s. This code need to be updated." )
def __init__(self, id_name, local_path, href, rev): self.client = ctx_svn_client.CTXSubversionClient() self.path = os.path.join(local_path, id_name) if href == None: # Try to get href from local copy href = self.client.getURLFromWorkingCopy( self.path ) if href == None: userErrorExit("No HREF specified for repository '%s'. Failed to aquire HREF from local copy '%s'"\ %(id_name, self.path)) CTXRepository.__init__( self, id_name, local_path, href, rev, version_control=True ) self.msgSender = "CTXRepositorySVN"
def __init__(self, id_name, local_path, href, rev): self.path = os.path.join(local_path, id_name) if href == None: # No remote repo source given, see if we have a local representation if os.path.exists( self.path ): href = self.path if href == None: userErrorExit("No HREF specified for repository '%s'. Failed to aquire HREF from local copy '%s'"\ %(id_name, self.getAbsLocalPath())) CTXRepository.__init__( self, id_name, local_path, href, None, version_control=False ) self.msgSender = "CTXRepositoryFS"
def checkout( self, url, local_directory, revision ): self.resetClient() if self.isWorkingCopy( local_directory ): userErrorExit("Unable to checkout '%s', given target directory '%s' is an existing working copy."\ %(url, local_directory)) if not self.isRepoURL(url): userErrorExit("Invalid SVN repository: '%s'"%(url)) rev = self.prepareRevision(revision) if not os.path.isdir(local_directory): userErrorExit("Checkout destination '%s' is not a directory"%(local_directory)) try: #pysvn checkout seems to have a problem when spaces are not escaped but also when other characters are escaped url = urllib.quote(url, safe=',~=!@#$%^&*()+|}{:?><;[]\\/') self.client.checkout(url=url, path=local_directory, recurse=True, revision=rev) except pysvn.ClientError, e: for message, code in e.args[1]: if code in [ERR_HOST_UNRESOLVED,]: errorMessage("Unable to resolve host '%s'. Proceeding.. "%(url)) else: userErrorExit("Unknown failure when checking out '%s'\nPYSVN Exception:\n%s (%d)"%(url, message, code))
def validateRepositories( self ): all_valid = True if not self.hasRSpec(): return for repo in self.getRSpec().getRepositories(): infoMessage("Validating repository '%s'"%(repo.getID()), 1) if not repo.checkValid( self.updating ): all_valid = False if all_valid == False: userErrorExit("Validation failed.")
def receive( self ): import pickle import sys data_buffer = str(sys.stdin.read()) # # Locate package header # i = data_buffer.rfind( export_header ) if i == -1: print data_buffer #Most likely errors from main system infoMessage("\n********** Export handler entry point **********\n\n", 2) userErrorExit("Unable to receive export package. Export header not found.\nThis is commonly the consequence of a terminal error raised by Contexo.") # # Extract package size # i += len(export_header) size_s = "" header_len = len(export_header) while data_buffer[i] != '$': size_s += data_buffer[i] header_len += 1 i += 1 header_len += 1 package_start = i+1 package_size = int(size_s) package_end = package_start + package_size # # Extract package chunk, and print everything else as regular text # package_dump = data_buffer[ package_start : package_end ] print data_buffer[ 0 : package_start - header_len ] print data_buffer[ package_end : -1 ] infoMessage("\n********** Export handler entry point **********\n\n", 2) # # Unpickle # self.export_data = pickle.loads( package_dump )
def receive( self ): import pickle import sys data_buffer = str(sys.stdin.read()) # # Locate package header # i = data_buffer.rfind( export_header ) if i == -1: print data_buffer #Most likely errors from main system infoMessage("\n********** Export handler entry point **********\n\n", 2) userErrorExit("Ctx export failed because of previous errors! Check the log for previous errors.") # # Extract package size # i += len(export_header) size_s = "" header_len = len(export_header) while data_buffer[i] != '$': size_s += data_buffer[i] header_len += 1 i += 1 header_len += 1 package_start = i+1 package_size = int(size_s) package_end = package_start + package_size # # Extract package chunk, and print >>sys.stderr, everything else as regular text # package_dump = data_buffer[ package_start : package_end ] print data_buffer[ 0 : package_start - header_len ] print data_buffer[ package_end : -1 ] infoMessage("\n********** Export handler entry point **********\n\n", 2) # # Unpickle # self.export_data = pickle.loads( package_dump )
def getLocalAccessPath(self): local_access_path = None if self.rcs == None: infoMessage("No RCS specified for RSpec '%s', attempting regular file access"\ %(self.getHref()), 4) if not os.path.exists(self.href): userErrorExit("RSpec unreachable with regular file access: \n %s"%(self.href)) local_access_path = self.getHref() else: temp_dir = getUserTempDir() rspec_name = os.path.basename(self.getHref()) temp_rspec = os.path.join( temp_dir, rspec_name ) infoMessage("Downloading (svn-exporting) RSpec from '%s' to '%s' using RCS '%s'"\ %(str(self.getHref()), str(temp_rspec), str(self.rcs)), 1) if os.path.exists(temp_rspec): os.remove( temp_rspec ) # rspec access is still handled by svn if self.rcs == 'svn' or self.rcs == 'git': svn = ctx_svn_client.CTXSubversionClient() svn.export( self.getHref(), temp_dir, self.revision ) local_access_path = temp_rspec #elif self.rcs == 'git': #git = ctx_git_client.CTXGitClient() else: userErrorExit("Unsupported RCS: %s"%(self.rcs)) infoMessage("RSpec local access path resolved to: %s"\ %(local_access_path), 4) return local_access_path
def __init__(self, id_name, local_path, href, rev): self.path = os.path.abspath('') self.destpath = os.path.join(local_path, id_name) self.id_name = id_name self.git = locate_git() self.rev = rev if href == None: userErrorExit("No HREF specified for repository '%s'. Failed to aquire HREF from local copy '%s'"\ %(id_name, self.getAbsLocalPath())) CTXRepository.__init__( self, id_name, local_path, href, rev, version_control=True ) # these are hardcoded dummy paths for ctxview self.local_path = local_path self.codeModulePaths = ['dummy1'] self.componentPaths = ['dummy2'] # END hardcoded dummy paths self.msgSender = "CTXRepositoryGIT"
def updateWorkingCopy( self, lc_path, rev ): self.resetClient() if not self.isWorkingCopy( lc_path ): userErrorExit("Unable to update '%s'. Not a valid working copy."\ %(lc_path)) if rev.upper() == 'HEAD': rev = pysvn.Revision(pysvn.opt_revision_kind.head ) else: rev = pysvn.Revision(pysvn.opt_revision_kind.number, rev ) try: self.client.update( path=lc_path, recurse=True, revision=rev ) except pysvn.ClientError, e: for message, code in e.args[1]: if code in [ERR_HOST_UNRESOLVED,]: errorMessage("Unable to resolve host '%s'. Proceeding.. "\ %(self.getURLFromWorkingCopy(lc_path))) else: userErrorExit("Unknown failure when updating '%s'\nPYSVN Exception:\n%s (%d)"%(lc_path, message, code))
def __init__(self, view_path=str(), updating=False, validate=False ): self.localPath = os.path.abspath(view_path) if self.localPath.find(" ") > 0: userErrorExit("View dir name or any of it's subdirectories cannot contain space characters. View dir resolved to: \"" + self.localPath + "\"") self.global_paths = dict() # {section: pathlist}, where 'section' is any of SYSGLOBAL_PATH_SECTIONS self.rspec = None self.updating = updating # True when the view is being updated instead of used for building self.msgSender = "CTXView" infoMessage("Using view: %s "%(self.getRoot()), 2) for sec in SYSGLOBAL_PATH_SECTIONS: self.global_paths[sec] = list() self.process_view_directory() self.set_global_config() os.chdir( self.getRoot() ) if validate: self.validateRepositories() else: infoMessage("Skipping repository validation", 2);
def locateItem(self, item, path_sections): candidate_locations = list() tried_locations = list() path_sections = assureList( path_sections ) for path_section in path_sections: # Always prioritize locating items from the RSpec repositories if path_section in REPO_PATH_SECTIONS and self.getRSpec() != None: for repo in self.getRSpec().getRepositories(): repo_candidates, repo_tried = repo.locateItem( item, path_section ) candidate_locations.extend( repo_candidates ) tried_locations.extend( repo_tried ) if len(candidate_locations) == 1: infoMessage("Located '%s' at '%s'"%(item, candidate_locations[0]), 2) return candidate_locations[0] elif len(candidate_locations) > 1: userErrorExit("Multiple occurances of '%s' was found. Unable to determine which one to use: \n %s"\ %(item, "\n ".join(candidate_locations))) # Item not present in any repository, be clear to the user.. if self.getRSpec() != None: if self.getAccessPolicy() == AP_NO_REMOTE_ACCESS: infoMessage("Item '%s' was not found in RSpec repositories.\nNote that the system is set to search for repository items in the local view only (%s).\nTrying system global locations."%(item, AP_FLAGS[self.getAccessPolicy()]), 2) elif self.getAccessPolicy() == AP_PREFER_REMOTE_ACCESS: infoMessage("Item '%s' was not found in RSpec repositories.\nNote that the system is set to search for repository items at the repository source location only (%s).\nTrying system global locations."%(item, AP_FLAGS[self.getAccessPolicy()]), 2) else: infoMessage("Item '%s' was not found in RSpec repositories.\nTrying system global locations."%(item), 2) for path_section in path_sections: # File was not found in RSpec repositories, look in view if path_section in SYSGLOBAL_PATH_SECTIONS: for path in self.getGlobalPaths(path_section): tried_locations.append( path ) if os.path.isdir(path): if item in os.listdir(path): candidate_locations.append( os.path.join(path, item) ) else: tried_locations[-1] = tried_locations[-1] + " (path not found)" warningMessage("System global path '%s' doesn't exist"%(path)) if len(candidate_locations) == 1: infoMessage("Located '%s' at '%s'"%(item, candidate_locations[0]), 2) return candidate_locations[0] elif len(candidate_locations) > 1: userErrorExit("Multiple occurances of '%s' was found. Unable to determine which one to use: \n %s"\ %(item, "\n ".join(candidate_locations))) userErrorExit("Unable to locate file '%s'. Attempted the following locations: \n %s"\ %(item, "\n ".join(tried_locations)))
def getLocalAccessPath(self): # TODO: wipe cache if root element and first export ok src = str() local_access_path = os.path.join( self.rspec_cache_dir, os.path.basename(self.getHref())) if not os.path.exists(self.rspec_cache_dir): os.makedirs(self.rspec_cache_dir) if self.rcs == None: if not os.path.exists( local_access_path ): infoMessage("No RCS specified for RSpec '%s', attempting regular file access"\ %(self.getHref()), 4) if not os.path.exists(self.href): userErrorExit("RSpec unreachable with regular file access: \n %s"%(self.href)) shutil.copyfile( self.getHref(), local_access_path ) # access the local rspec if accessable # otherwise the user may be confused why changes in a locally modified would not be applied. if os.path.exists(self.href): local_access_path = self.getHref() else: if self.updating == True or not os.path.exists( local_access_path ): temp_dir = getUserTempDir() rspec_name = os.path.basename(self.getHref()) temp_rspec = os.path.join( temp_dir, rspec_name ) infoMessage("Downloading (svn-exporting) RSpec from '%s' to '%s' using RCS '%s'"\ %(str(self.getHref()), str(temp_rspec), str(self.rcs)), 1) if os.path.exists(temp_rspec): os.remove( temp_rspec ) # rspec access is still handled by svn if self.rcs == 'svn' or self.rcs == 'git': svn = ctx_svn_client.CTXSubversionClient() # does this fail if rspec cannot be fetched? svn.export( self.getHref(), temp_dir, self.revision ) if not os.path.exists( os.path.join(temp_dir, os.path.basename(self.getHref()))): userErrorExit("RSpec unreachable with remote Subversion access: \n %s"%(self.getHref())) else: userErrorExit("Unsupported RCS: %s"%(self.rcs)) src = os.path.join( temp_dir, rspec_name) shutil.copyfile( src, local_access_path ) infoMessage("RSpec local access path resolved to: %s"\ %(local_access_path), 4) return local_access_path
def locateItem(self, item, path_sections): candidate_locations = list() tried_locations = list() path_sections = assureList( path_sections ) for path_section in path_sections: # Always prioritize locating items from the RSpec repositories if path_section in REPO_PATH_SECTIONS and self.getRSpec() != None: for repo in self.getRSpec().getRepositories(): repo_candidates, repo_tried = repo.locateItem( item, path_section ) candidate_locations.extend( repo_candidates ) tried_locations.extend( repo_tried ) if len(candidate_locations) == 1: infoMessage("Located '%s' at '%s'"%(item, candidate_locations[0]), 2) return candidate_locations[0] elif len(candidate_locations) > 1: userErrorExit("Multiple occurances of '%s' was found. Unable to determine which one to use: \n %s"\ %(item, "\n ".join(candidate_locations))) infoMessage("Item '%s' was not found in RSpec repositories.\nTrying system global locations."%(item), 2) for path_section in path_sections: # File was not found in RSpec repositories, look in view if path_section in SYSGLOBAL_PATH_SECTIONS: for path in self.getGlobalPaths(path_section): tried_locations.append( path ) if os.path.isdir(path): if item in os.listdir(path): candidate_locations.append( os.path.join(path, item) ) else: tried_locations[-1] = tried_locations[-1] + " (path not found)" warningMessage("System global path '%s' doesn't exist"%(path)) if len(candidate_locations) == 1: infoMessage("Located '%s' at '%s'"%(item, candidate_locations[0]), 2) return candidate_locations[0] elif len(candidate_locations) > 1: userErrorExit("Multiple occurances of '%s' was found. Unable to determine which one to use: \n %s"\ %(item, "\n ".join(candidate_locations))) userErrorExit("Unable to locate file '%s'. Attempted the following locations: \n %s"\ %(item, "\n ".join(tried_locations)))
def export( self, url, local_directory, revision ): self.resetClient() if not self.isRepoURL(url): userErrorExit("Invalid SVN repository: '%s'"%(url)) rev = self.prepareRevision(revision) if not os.path.isdir( local_directory ): os.makedirs( local_directory ) elif self.isWorkingCopy( local_directory ): userErrorExit("Export destination '%s' is an existing working copy"%(local_directory)) export_dest = os.path.join( local_directory, os.path.basename(url) ) try: url = urllib.quote(url, safe=',~=!@#$%^&*()+|}{:?><;[]\\/') self.client.export(src_url_or_path=url, dest_path=export_dest, force=False, revision=rev) except : userErrorExit("Exception caught from pysvn: \n%s"%(sys.exc_value))
def locate_git(): for git_cand in ['git', 'git.cmd', 'git.exe', 'git.bat']: for path in os.environ["PATH"].split(os.pathsep): if os.path.exists(os.path.join( path, git_cand)) and os.access( os.path.join( path, git_cand), os.X_OK): return git_cand userErrorExit("Git cannot be found in your PATH. Please re-install Git and make sure the git.cmd, git.exe or git binary can be found in your PATH")
def startElement(self, name, attrs): # ..................................................................... if name == 'ctx-rspec': if self.parent_element.peek() != None: userErrorExit("'<ctx-rspec>' can only be used as root element") # ..................................................................... elif name == 'ctx-import': # Make sure this element is used in correct context if self.parent_element.peek() != 'ctx-rspec': userErrorExit("'%s' elements can only be used within '%s' elements"%(name, 'ctx-rspec')) # # Digest import and check for errors/inconsistencies # href = attrs.get('href', None) if href == None: userErrorExit("<ctx-import>: Missing mandatory attribute '%s' in RSpec '%s'"%('href', self.rspecFile.getFilename())) rcs = attrs.get('rcs', None) if rcs == None and attrs.has_key('rev'): userErrorExit("<ctx-import>: Revision ('rev') specified without specifying 'rcs' in RSpec '%s'"%(self.rspecFile.getFilename())) rev = attrs.get('rev', None ) if rcs != None and rev == None: warningMessage("<ctx-import>: No revision specified for import in RSpec '%s'. Assuming 'HEAD'"%(self.rspecFile.getFilename())) rev = 'HEAD' # Prepare locator object and add import to current RSpec rspecFileLocator = RSpecFileLocator( rcs=rcs, href=href, revision=rev, updating = False, wipe_cache=False, view=self.view ) self.rspecFile.addImport( rspecFileLocator ) # POINT OF RECURSION # ..................................................................... elif name == 'ctx-repo': # Make sure this element is used in correct context if self.parent_element.peek() != 'ctx-rspec': userErrorExit("'%s' elements can only be used within '%s' elements"%(name, 'ctx-rspec')) # Make sure 'id' attribute is unique within RSpec if attrs.has_key('id'): if attrs.get('id') in self.id_list: userErrorExit("Multiple occurances of id '%s' in '%s'"%(attrs.get('id'), self.rspecFile.getFilename())) else: self.id_list.append(attrs.get('id')) self.current_repo = createRepoFromRCS( attrs.get('rcs', None), attrs.get('id', ""), attrs.get('path', ""), attrs.get('href', ""), attrs.get('rev', "")) self.rspecFile.addRepository ( self.current_repo ) # ..................................................................... elif name == 'ctx-path': # Make sure this element is used in correct context if self.parent_element.peek() not in ['ctx-repo',]: userErrorExit("'<%s>' elements cannot be used within '<%s>' elements"%(name, self.parent_element.peek())) # # Assure presence of mandatory attributes # attribute = 'type' if not attrs.has_key(attribute): userErrorExit("Missing mandatory attribute '%s' in element '<%s>'"%(attribute, name)) attribute = 'spec' if not attrs.has_key(attribute): userErrorExit("Missing mandatory attribute '%s' in element '<%s>'"%(attribute, name)) ctx_path_type = attrs.get( 'type' ).lower() self.current_repo.addPath( ctx_path_type, attrs.get('spec').replace('\\','/') ) # ..................................................................... else: warningMessage("Ignoring unknown element '<%s>' in RSpec '%s'.\nThis might be a normal compatibility issue."%(name, self.rspecFile.getFilename())) self.parent_element.push( name )