Exemple #1
0
	def getTarball(self, importpath, commit):
		"""
		Search for a tarball in tarball directory.
		If it does not exist, download the tarball.

		TODO: Create a DirectoryStorage on top of TarballStorage?
		1) extract the archive to 
		2) rename its directory to TARBALLSIGNATURE_DIR
		3) return TARBALLSIGNATURE_DIR
		"""
		# tarball directory must exist
		if not os.path.exists(self.tarball_directory):
			self.err = "Tarball directory %s does not exist" % self.tarball_directory
			return ""

		ri = RepositoryInfo(importpath, commit)
		if not ri.retrieve():
			self.err = ri.getError()
			return ""

		# tarball exists?
		tarball_path = "%s/%s" % (self.tarball_directory, ri.getSignature())
		if not os.path.exists(tarball_path):
			ai = ri.getArchiveInfo()
			if self.verbose:
				print "Downloading %s ..." % ai.archive_url
			# download tarball
			so, se, rc = runCommand("wget -nv %s --no-check-certificate -O %s" % (ai.archive_url, tarball_path))
			if rc != 0:
				print "Unable to download tarball:\n%s" % (se)
				return ""

		return tarball_path
Exemple #2
0
    def decodeRepository(self):
        # get repository info
        self.repository_info = RepositoryInfo(self.import_path, self.commit)
        if not self.repository_info.retrieve():
            self.err = self.repository_info.getError()
            return False

        # package name
        ip_info = self.repository_info.getImportPathInfo()

        r_info = self.repository_info.getArchiveInfo()

        self.repository_decoded = True
        self.archive_dir = r_info.archive_dir
        self.name = ip_info.getPackageName()
        return True
Exemple #3
0
    def __init__(self, workTree, gitDir=None, repoFlags=None):
        """Initialize a Repository object."""
        self.workTree = workTree
        if gitDir is None:
            self.gitDir = workTree + '/.git'
        else:
            self.gitDir = gitDir

        if repoFlags is None:
            self.repoFlags = RepositoryFlags()
        else:
            self.repoFlags = repoFlags

        self.repoInfo = RepositoryInfo(self.repoFlags)
        self.submoduleUTD = False
        self.workingTreeUTD = False
        self.submodules = list()
Exemple #4
0
    def getTarball(self, importpath, commit):
        """
		Search for a tarball in tarball directory.
		If it does not exist, download the tarball.

		TODO: Create a DirectoryStorage on top of TarballStorage?
		1) extract the archive to 
		2) rename its directory to TARBALLSIGNATURE_DIR
		3) return TARBALLSIGNATURE_DIR
		"""
        # tarball directory must exist
        if not os.path.exists(self.tarball_directory):
            self.err = "Tarball directory %s does not exist" % self.tarball_directory
            return ""

        ri = RepositoryInfo(importpath, commit)
        if not ri.retrieve():
            self.err = ri.getError()
            return ""

        # tarball exists?
        tarball_path = "%s/%s" % (self.tarball_directory, ri.getSignature())
        if not os.path.exists(tarball_path):
            ai = ri.getArchiveInfo()
            if self.verbose:
                print "Downloading %s ..." % ai.archive_url
            # download tarball
            so, se, rc = runCommand(
                "wget -nv %s --no-check-certificate -O %s" %
                (ai.archive_url, tarball_path))
            if rc != 0:
                print "Unable to download tarball:\n%s" % (se)
                return ""

        return tarball_path
Exemple #5
0
	def decodeRepository(self):
		# get repository info
		self.repository_info = RepositoryInfo(self.import_path, self.commit)
		if not self.repository_info.retrieve():
			self.err = self.repository_info.getError()
			return False

		# package name
		ip_info = self.repository_info.getImportPathInfo()

		r_info = self.repository_info.getArchiveInfo()

		self.repository_decoded = True
		self.archive_dir = r_info.archive_dir
		self.name = ip_info.getPackageName()
		return True
Exemple #6
0
class PackageInfo:
    """
	Get basic information about project:
		imported packages
		provided packages
		tests
	"""
    def __init__(self, import_path, commit="", noGodeps=[]):
        self.import_path = import_path
        self.commit = commit
        self.noGodeps = noGodeps
        self.err = ""
        self.repository_info = None
        self.project_info = None
        self.archive_dir = ""
        self.repository_decoded = False
        self.name = ""

    def getError(self):
        return self.err

    def getName(self):
        return self.name

    def getRepositoryInfo(self):
        return self.repository_info

    def getProjectInfo(self):
        return self.project_info

    def decodeRepository(self):
        # get repository info
        self.repository_info = RepositoryInfo(self.import_path, self.commit)
        if not self.repository_info.retrieve():
            self.err = self.repository_info.getError()
            return False

        # package name
        ip_info = self.repository_info.getImportPathInfo()

        r_info = self.repository_info.getArchiveInfo()

        self.repository_decoded = True
        self.archive_dir = r_info.archive_dir
        self.name = ip_info.getPackageName()
        return True

    def decodeProject(self, working_directory="."):
        if not self.repository_decoded:
            self.err = "RepositoryInfo not decoded"
            return False

        # get package info
        self.project_info = ProjectInfo(self.noGodeps)
        source_code_directory = "%s/%s" % (working_directory, self.archive_dir)
        if not os.path.exists(source_code_directory):
            self.err = "Source code directory %s does not exist." % source_code_directory
            self.err += "CWD: %s" % os.getcwd()
            return False

        if not self.project_info.retrieve(source_code_directory):
            self.err = self.project_info.getError()
            return False

        return True
Exemple #7
0
class Repository:
    """Repository:
    Class representing a Git repository.
    """
    def __init__(self, workTree, gitDir=None, repoFlags=None):
        """Initialize a Repository object."""
        self.workTree = workTree
        if gitDir is None:
            self.gitDir = workTree + '/.git'
        else:
            self.gitDir = gitDir

        if repoFlags is None:
            self.repoFlags = RepositoryFlags()
        else:
            self.repoFlags = repoFlags

        self.repoInfo = RepositoryInfo(self.repoFlags)
        self.submoduleUTD = False
        self.workingTreeUTD = False
        self.submodules = list()

    def status(self, stats, begin=''):
        """
        PUBLIC. Get status of the repository
        """
        if not self.workingTreeUTD:
            self.populateRepoInfo()

        if self.repoFlags.getSubmodules() and not self.submoduleUTD:
            self.populateSubmoduleInfo()

        stats = self.makeSummaryString(stats, begin=begin)
        return (self.repoInfo.hasChanges(), stats)

    def makeSummaryString(self, stats, begin=''):
        """
        INTERNAL. Performs string operations to generate the status string that
        might get printed by the caller. This method treats `stats' like a
        terminal object.
        """
        # Replace $HOME with '~' for printing
        repoPath = self.workTree.replace(os.environ['HOME'], "~")
        # Remove a trailing slash, if it exists
        if repoPath[len(repoPath) - 1] == '/':
            repoPath = repoPath[:-1]

        # Do (ERE) 's#//+#/#g'
        stats = '/'.join(filter(None, stats.split('/')))  # s'#//\+##g'
        # Prepare status string
        repoStatus = stats + str(self.repoInfo) + ' ' + repoPath + '\n'

        # Put together the status string for submodules
        if self.repoFlags.getSubmodules():
            for module in self.submodules:
                submoduleStatus = begin + '\t'
                changes, submoduleStatus = module.status(submoduleStatus,
                                                         begin=begin + '\t')
                # Print all submodules if -v is specified
                if changes or self.repoFlags.getVerbose():
                    # Print the whole path of the submodule if -v is specified
                    if self.repoFlags.getVerbose():
                        repoStatus = (repoStatus + submoduleStatus)
                    else:
                        repoStatus = (repoStatus +
                                      submoduleStatus.replace(repoPath, ''))
        return repoStatus

    def populateRepoInfo(self):
        """
        INTERNAL. Execute Git commands to populate the fields of this
        RepositoryInfo object.
        """
        self.checkWorkingTree()
        self.checkBugs()
        self.checkStash()
        self.checkRemotes()

        self.workingTreeUTD = True
        return self.repoInfo.hasChanges()

    def checkWorkingTree(self):
        """
        INTERNAL. Runs git commands to check the status of the working tree and
        populates the RepositoryInfo object as a side effect
        """
        cmd = ('git --git-dir=xGD --work-tree=xWT status'
               ' --ignore-submodules'
               ' --short')
        pipe = self.execGit(
            cmd.replace('xGD', self.gitDir).replace('xWT', self.workTree))

        # Parse the output and populate the fields.
        for line in pipe.stdout.readlines():
            line = line.decode('utf-8').split(' ')
            if line[0] and '?' not in line[0]:
                self.repoInfo.getTreeInfo().setStaged(1)
                self.repoInfo.setChanges(True)
            if (len(line[0]) > 1 and '?' not in line[0]) \
               or (not line[0] and line[1]):
                self.repoInfo.getTreeInfo().setUnstaged(1)
                self.repoInfo.setChanges(True)
            elif '?' in line[0]:
                self.repoInfo.getTreeInfo().setUntracked(1)
                self.repoInfo.setChanges(True)

    def checkBugs(self):
        """
        INTERNAL. Checks the status of the Repository's bugs file and set the
        corresponding fields in this RepositoryInfo object.
        """
        if self.repoFlags.getBugs():
            try:
                with open(self.workTree + '/bugs', 'r'):
                    self.repoInfo.getBugInfo().setBugs(True)
                    self.repoInfo.setChanges(True)
            except FileNotFoundError:
                pass

    def checkStash(self):
        """
        INTERNAL. Check the status of the repository's stash, and the number of
        entries therein.
        """
        if self.repoFlags.getStash():
            try:
                with open(self.gitDir + '/refs/stash', 'r') as stashFile:
                    (self.repoInfo.getStashInfo().setStashEntries(
                        len(stashFile.readlines())))
                    self.repoInfo.setChanges(True)
            except FileNotFoundError:
                pass

    def checkRemotes(self):
        """
        INTERNAL. Compare refs of the local branches against the remote refs
        """
        # TODO: Refactor Repository.checkRemotes()
        if not self.repoFlags.getRemotes():
            return

        # Update remote refs
        self.execGit('git remote update')

        # Get the name of the refs
        localRefs = os.listdir(self.gitDir + '/refs/heads')
        remoteRefs = list()
        try:
            for remote in os.listdir(self.gitDir + '/refs/remotes'):
                for ref in os.listdir(self.gitDir + '/refs/remotes/' + remote):
                    remoteRefs.append(remote + '/' + ref)
        except FileNotFoundError:
            for local in localRefs:
                (self.repoInfo.getBranchInfo().setBranchStatus(
                    local, BranchStatus.NO_REMOTE))

        # There's likely to be fewer locals than remotes (in large projects)
        for local in localRefs:
            remote = None
            for ref in remoteRefs:
                pieces = ref.split('/')
                if local == pieces[-1]:
                    # Remote refs in git are labelled remote/branch
                    remote = '/'.join(pieces[-2:])
                    break

            if remote is None:
                (self.repoInfo.getBranchInfo().setBranchStatus(
                    local, BranchStatus.NO_REMOTE))
                continue

            revParseCmd = 'git --git-dir=xGD --work-tree=xWT rev-parse '
            mergeBaseCmd = 'git --git-dir=xGD --work-tree=xWT merge-base '
            localHash = (self.execGit(
                revParseCmd.replace('xGD', self.gitDir).replace(
                    'xWT', self.workTree) + str(local)).stdout.readlines()[0])
            remoteHash = (self.execGit(
                revParseCmd.replace('xGD', self.gitDir).replace(
                    'xWT', self.workTree) + str(remote)).stdout.readlines()[0])
            baseHash = (self.execGit(
                mergeBaseCmd.replace('xGD', self.gitDir).replace(
                    'xWT', self.workTree) + str(local) + ' ' +
                str(remote)).stdout.readlines()[0])

            # Compare the hashes and set the status of the branch.
            if localHash == remoteHash:
                (self.repoInfo.getBranchInfo().setBranchStatus(
                    local, BranchStatus.UP_TO_DATE))
            elif localHash == baseHash:
                (self.repoInfo.getBranchInfo().setBranchStatus(
                    local, BranchStatus.BEHIND))
                self.repoInfo.setChanges(True)
            elif remoteHash == baseHash:
                (self.repoInfo.getBranchInfo().setBranchStatus(
                    local, BranchStatus.AHEAD))
                self.repoInfo.setChanges(True)
            else:
                (self.repoInfo.getBranchInfo().setBranchStatus(
                    local, BranchStatus.DIVERGED))
                self.repoInfo.setChanges(True)

    def populateSubmoduleInfo(self):
        """INTERNAL. Execute Git commands to populate self.submodules"""
        entries = self.parseModuleFile(self.workTree + '/.gitmodules')
        for entry in entries:
            # Instantiate the submodule
            submodule = Repository(
                workTree=(self.workTree + '/' + entry['path']),
                gitDir=(self.gitDir + '/modules/' + entry['name']),
                repoFlags=self.repoFlags)
            if submodule.populateRepoInfo():
                self.repoInfo.setChanges(True)
            if submodule.populateSubmoduleInfo():
                self.repoInfo.setChanges(True)

            self.submodules.append(submodule)

        self.submoduleUTD = True
        return self.repoInfo.hasChanges()

    @staticmethod
    def parseGitmodules(lines):
        """
        INTERNAL. Assumes moduleFile is a list of lines from a .gitmodules file
        and parses it accordingly.
        """
        # TODO: Move git specific logic to separate module
        #   * And use dependency injection to populate Repository
        #   * Alternatively, use inheritance: class GitRepository(Repository)
        try:
            while True:
                line = lines.pop(0)
                while line[0] != '[':
                    line = lines.pop(0)

                # Get the module name
                moduleName = line.split('"')[1]

                line = lines.pop(0)
                # Get the module path
                modulePath = ''
                while line[0] in (' ', '\t'):
                    pieces = line.split()
                    if pieces[0] == 'path':
                        modulePath = pieces[2]
                        break
                    line = lines.pop(0)

                # Create the entry
                entries.append({'name': moduleName, 'path': modulePath})
        except IndexError:
            pass

    @staticmethod
    def parseModuleFile(path):
        """INTERNAL. Parse the .gitmodules file @ path into a list of dicts."""
        entries = list()
        try:
            with open(path, 'r') as gitmodules:
                # Parse the .gitmodules file.
                lines = gitmodules.readlines()
                entries = parseGitmodules(lines)
        except FileNotFoundError:
            pass
        return entries

    @staticmethod
    def execGit(cmd):
        """INTERNAL. Spawns a subprocess to execute a git command"""
        pipe = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
        pipe.wait()
        if pipe.returncode != 0:
            raise SystemError(('git did not exit successfully. Command:\n'
                               '{}').format(cmd))
        return pipe
Exemple #8
0
class PackageInfo:
	"""
	Get basic information about project:
		imported packages
		provided packages
		tests
	"""
	def __init__(self, import_path, commit = "", noGodeps = [], skip_errors=False):
		self.import_path = import_path
		self.commit = commit
		self.noGodeps = noGodeps
		self.err = ""
		self.repository_info = None
		self.project_info = None
		self.archive_dir = ""
		self.repository_decoded = False
		self.name = ""
		self.skip_errors = skip_errors

	def getError(self):
		return self.err

	def getName(self):
		return self.name

	def getRepositoryInfo(self):
		return self.repository_info

	def getProjectInfo(self):
		return self.project_info

	def decodeRepository(self):
		# get repository info
		self.repository_info = RepositoryInfo(self.import_path, self.commit)
		if not self.repository_info.retrieve():
			self.err = self.repository_info.getError()
			return False

		# package name
		ip_info = self.repository_info.getImportPathInfo()

		r_info = self.repository_info.getArchiveInfo()

		self.repository_decoded = True
		self.archive_dir = r_info.archive_dir
		self.name = ip_info.getPackageName()
		return True

	def decodeProject(self, working_directory = "."):
		if not self.repository_decoded:
			self.err = "RepositoryInfo not decoded"
			return False

		# get package info
		self.project_info = ProjectInfo(self.noGodeps)
		source_code_directory = "%s/%s" % (working_directory, self.archive_dir)
		if not os.path.exists(source_code_directory):
			self.err = "Source code directory %s does not exist." % source_code_directory
			self.err += "CWD: %s" % os.getcwd()
			return False

		if not self.project_info.retrieve(source_code_directory, self.skip_errors):
			self.err = self.project_info.getError()
			return False

	
		return True