<commit_before>#
# Copyright (c) 2004 Specifix, Inc.
# All rights reserved
#

import changeset
import dbhash
import files
import os
import repository
import versions

# Many comments in this file only make sense if you consider the case
# where something is being updated from version A to B, and the local
# branches are called A.local and B.local; this terminology is used throughout
# the comments in this file

# Every item which is inserted into the database really goes in twice;
# once as is, and then a LocalBranch is immediately created which reflects
# what's in the file system. The "as is" copy doesn't include data for
# any file except configuration files (which means while they can be used
# as the source for a change set, they can't be used as the target)
#
# The LocalBranch for each item in the database has normal header information,
# but the on-disk files are the real source of information on the package,
# including file types, hashes, etc

class Database(repository.LocalRepository):

    # If the request is for the head element of the local branch, we need
    # to be a bit careful with the file list. It currently contains the
    # branched version of each file, but we want to contain the non-branch
    # version if the branch (that is, the local filesystem) hasn't changed
    def getPackageVersion(self, name, version):
	pkg = repository.LocalRepository.getPackageVersion(self, name, version)
	if not version.isLocal(): return pkg
	head = self.pkgLatestVersion(name, version.branch())
	if not version.equal(head): return pkg

	for (fileId, path, fileVersion) in pkg.fileList():
	    parentVersion = fileVersion.parent()

	    dbFile = self.getFileVersion(fileId, parentVersion)
	    localFile = self.getFileVersion(fileId, fileVersion, path = path)

	    if dbFile.same(localFile):
		pkg.updateFile(fileId, path, fileVersion.parent())

	return pkg

    # like getPackageVersion, we need to look to the filesystem for file
    # versions which are at the head of our local branch; this means that
    # we require the path to get information on some versions
    def getFileVersion(self, fileId, version, path = None, withContents = 0):
	head = self.fileLatestVersion(fileId, version.branch())
	if not version.isLocal() or (head and not version.equal(head)):
	    (file, contents) = repository.LocalRepository.getFileVersion(
					self, fileId, version, withContents = 1)

	    if withContents:
		return (file, contents)
	    return file

	assert(path)

	# we can't get the file flags or know if it's a source file by looking
	# in the filesystem; we don't let the user change those for the local
	# branch either
	parentV = version.parent()
	file = repository.LocalRepository.getFileVersion(self, fileId, parentV)
	if isinstance(file, files.SourceFile):
	    localFile = files.FileFromFilesystem(self.root + path, fileId,
						 type = "src")
	else:
	    localFile = files.FileFromFilesystem(self.root + path, fileId)

	localFile.flags(file.flags())

	if withContents:
	    if isinstance(file, files.RegularFile): 
		cont = repository.FileContentsFromFilesystem(self.root + path)
	    else:
		cont = None

	    return (localFile, cont)

	return localFile

    # takes an abstract change set and creates a differential change set 
    # against a branch of the repository
    def rootChangeSet(self, absSet, branch):
	assert(absSet.isAbstract())

	# this has an empty source path template, which is only used to
	# construct the eraseFiles list anyway
	(pkgList, fileList, fileMap, oldFileList, oldPackageList, 
	    eraseList, eraseFiles) = self._buildChangeSetJob("", absSet)

	# abstract change sets cannot have eraseLists
	assert(not eraseList)
	assert(not eraseFiles)

	cs = changeset.ChangeSetFromAbstractChangeSet(absSet)

	# we want to look up file objects by fileId
	idToFile = {}
	for (fileId, fileVersion, file, saveContents) in fileList:
	    idToFile[fileId] = (fileVersion, file)

	for (pkgName, newPkg, newVersion) in pkgList:
	    # FIXME
	    #
	    # this shouldn't be against branch, it should be against
	    # the version of the package already installed on the
	    # system. unfortunately we can't represent that yet. 
	    oldVersion = self.pkgLatestVersion(pkgName, branch)
	    if not oldVersion:
		# new package; the Package.diff() right after this never
		# sets the abstract flag, so the right thing happens
		old = None
	    else:
		old = self.getPackageVersion(pkgName, oldVersion)

	    (pkgChgSet, filesNeeded) = newPkg.diff(old)
	    cs.newPackage(pkgChgSet)

	    for (fileId, oldVersion, newVersion) in filesNeeded:
		filedb = self._getFileDB(fileId)

		(ver, newFile) = idToFile[fileId]
		assert(ver.equal(newVersion))

		oldFile = None
		if oldVersion:
		    oldFile = filedb.getVersion(oldVersion)

		(filecs, hash) = changeset.fileChangeSet(fileId, oldFile, 
							 newFile)

		cs.addFile(fileId, oldVersion, newVersion, filecs)
		if hash: cs.addFileContents(hash)

	return cs

    # local changes includes the A->A.local portion of a rollback; if it
    # doesn't exist we need to compute that and save a rollback for this
    # transaction
    def commitChangeSet(self, cs, localRollback = None, sourcePath = "/"):
	assert(not cs.isAbstract())

	map = ( ( None, sourcePath + "/" ), )
	cs.remapPaths(map)

	# create the change set from A->A.local
	list = []
	for pkg in cs.getNewPackageList():
	    name = pkg.getName()
	    old = pkg.getOldVersion()
	    if self.hasPackage(name) and old:
		branch = old.fork(versions.LocalBranch(), sameVerRel = 0)
		new = self.pkgLatestVersion(name, branch)
		list.append((name, old, new, 0))

	localChanges = self.createChangeSet(list)
<commit_msg>updated rootChangeSet() to work with ChangeSetJob object<commit_after>#
# Copyright (c) 2004 Specifix, Inc.
# All rights reserved
#

import changeset
import dbhash
import files
import os
import repository
import versions

# Many comments in this file only make sense if you consider the case
# where something is being updated from version A to B, and the local
# branches are called A.local and B.local; this terminology is used throughout
# the comments in this file

# Every item which is inserted into the database really goes in twice;
# once as is, and then a LocalBranch is immediately created which reflects
# what's in the file system. The "as is" copy doesn't include data for
# any file except configuration files (which means while they can be used
# as the source for a change set, they can't be used as the target)
#
# The LocalBranch for each item in the database has normal header information,
# but the on-disk files are the real source of information on the package,
# including file types, hashes, etc

class Database(repository.LocalRepository):

    # If the request is for the head element of the local branch, we need
    # to be a bit careful with the file list. It currently contains the
    # branched version of each file, but we want to contain the non-branch
    # version if the branch (that is, the local filesystem) hasn't changed
    def getPackageVersion(self, name, version):
	pkg = repository.LocalRepository.getPackageVersion(self, name, version)
	if not version.isLocal(): return pkg
	head = self.pkgLatestVersion(name, version.branch())
	if not version.equal(head): return pkg

	for (fileId, path, fileVersion) in pkg.fileList():
	    parentVersion = fileVersion.parent()

	    dbFile = self.getFileVersion(fileId, parentVersion)
	    localFile = self.getFileVersion(fileId, fileVersion, path = path)

	    if dbFile.same(localFile):
		pkg.updateFile(fileId, path, fileVersion.parent())

	return pkg

    # like getPackageVersion, we need to look to the filesystem for file
    # versions which are at the head of our local branch; this means that
    # we require the path to get information on some versions
    def getFileVersion(self, fileId, version, path = None, withContents = 0):
	head = self.fileLatestVersion(fileId, version.branch())
	if not version.isLocal() or (head and not version.equal(head)):
	    (file, contents) = repository.LocalRepository.getFileVersion(
					self, fileId, version, withContents = 1)

	    if withContents:
		return (file, contents)
	    return file

	assert(path)

	# we can't get the file flags or know if it's a source file by looking
	# in the filesystem; we don't let the user change those for the local
	# branch either
	parentV = version.parent()
	file = repository.LocalRepository.getFileVersion(self, fileId, parentV)
	if isinstance(file, files.SourceFile):
	    localFile = files.FileFromFilesystem(self.root + path, fileId,
						 type = "src")
	else:
	    localFile = files.FileFromFilesystem(self.root + path, fileId)

	localFile.flags(file.flags())

	if withContents:
	    if isinstance(file, files.RegularFile): 
		cont = repository.FileContentsFromFilesystem(self.root + path)
	    else:
		cont = None

	    return (localFile, cont)

	return localFile

    # takes an abstract change set and creates a differential change set 
    # against a branch of the repository
    def rootChangeSet(self, absSet, branch):
	assert(absSet.isAbstract())

	# this has an empty source path template, which is only used to
	# construct the eraseFiles list anyway
	job = repository.ChangeSetJob(self, absSet)

	# abstract change sets cannot have eraseLists
	#assert(not eraseList)
	#assert(not eraseFiles)

	cs = changeset.ChangeSetFromAbstractChangeSet(absSet)

	for newPkg in job.newPackageList():
	    # FIXME
	    #
	    # this shouldn't be against branch, it should be against
	    # the version of the package already installed on the
	    # system. unfortunately we can't represent that yet. 
	    pkgName = newPkg.getName()
	    oldVersion = self.pkgLatestVersion(pkgName, branch)
	    if not oldVersion:
		# new package; the Package.diff() right after this never
		# sets the abstract flag, so the right thing happens
		old = None
	    else:
		old = self.getPackageVersion(pkgName, oldVersion)

	    (pkgChgSet, filesNeeded) = newPkg.diff(old, abstract = 0)
	    cs.newPackage(pkgChgSet)

	    for (fileId, oldVersion, newVersion, newPath) in filesNeeded:
		fileObj = job.getFile(fileId)
		assert(newVersion.equal(fileObj.version()))

		oldFile = None
		if oldVersion:
		    oldFile = self.getFileVersion(fileId, oldVersion)

		(filecs, hash) = changeset.fileChangeSet(fileId, oldFile, 
							 fileObj.file())

		cs.addFile(fileId, oldVersion, newVersion, filecs)
		if hash: cs.addFileContents(hash)

	return cs

    # local changes includes the A->A.local portion of a rollback; if it
    # doesn't exist we need to compute that and save a rollback for this
    # transaction
    def commitChangeSet(self, cs, localRollback = None, sourcePath = "/"):
	assert(not cs.isAbstract())

	map = ( ( None, sourcePath + "/" ), )
	cs.remapPaths(map)

	# create the change set from A->A.local
	list = []
	for pkg in cs.getNewPackageList():
	    name = pkg.getName()
	    old = pkg.getOldVersion()
	    if self.hasPackage(name) and old:
		branch = old.fork(versions.LocalBranch(), sameVerRel = 0)
		new = self.pkgLatestVersion(name, branch)
		list.append((name, old, new, 0))

	localChanges = self.createChangeSet(list)

{'fraction_non_alphanumeric': 0.08289273232368492, 'fraction_numerical': 0.0015234339994623174, 'mean_word_length': 3.9206349206349205, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '760641', 'n_tokens_mistral': 3443, 'n_tokens_neox': 3176, 'n_words': 1251}