不久前,我发现了LinuxFromScratch项目。在系统启动和工作之后(经过了很大的挣扎),我意识到如果我想继续使用LFS,某种类型的包管理将是非常好的。当然,我可以安装Pacman,apt,rpm等,就像任何理智的人一样。相反,我对创建自己的简单的“包管理”系统很感兴趣,这个系统可以跟踪属于某个包的文件,等等。
我已附上数份档案,其中两份特别需要检讨:
import io_crate, os.path, sqlite3, core_regex, datetime, io_output
class Package:
crate_extension = '.crate'
database_location = 'proto.db'
def __init__(self, name, verbosity = 0, fp = '/home/duncan/Documents/fakeroot', rp = '/home/duncan/Documents/install', ap = '/usr/src/archive/', cp = '/home/duncan/Documents/package/'):
# Setup database stuff
self.connection = sqlite3.connect(self.database_location)
self.connection.text_factory = str
self.db_cursor = self.connection.cursor()
# Setup path and name
self.name = name
self.fakeroot_path = os.path.join(fp, self.name)
self.root = rp
self.archive_path = ap
self.crate_path = os.path.join(cp, self.name) + self.crate_extension
# Setup description taken from .crate file
crate_contents = io_crate.read_crate(self.crate_path)
self.description = crate_contents[0][1]
self.homepage = crate_contents[1][1]
self.optional_deps = crate_contents[2][1]
self.recommended_deps = crate_contents[3][1]
self.required_deps = crate_contents[4][1]
self.verbosity = verbosity
def add_to_db(self):
"""Adds self.name to the package database."""
if self.is_in_db():
return 0
else:
# no need to try..except this because is_in_db.
self.db_cursor.execute('INSERT INTO Packages VALUES(?, ?);', (self.name, datetime.datetime.today()))
io_output.vbprint(self.verbosity, '{} added to the databased'.format(self.name))
return 1
def remove_from_db(self):
"""Removes self from the database of packages."""
if self.is_in_db():
self.db_cursor.execute('DELETE FROM Packages WHERE Package=?;', (self.name,))
io_output.vbprint(self.verbosity, '{} removed from database'.format(self.name))
return 1
return 0
def is_in_db(self):
"""Checks if the name of self is contained in the packages database."""
try:
self.db_cursor.execute('SELECT * FROM Packages WHERE Package=?;', (self.name,))
except:
print 'Couldn\'t read the database at {}'.format(self.database_location)
if not self.db_cursor.fetchone():
return 0
return 1
def __del__(self):
self.connection.commit()
self.connection.close()import os, md5_gen, shutil, io_output
class Fakeroot():
def __init__(self, package):
self.dirs = [] # A list based on the files in the fakeroot.
self.files = [] # A list of all the directories to be created in package.root.
self.links = [] # A list of links from the fakeroot
self.package = package
for root, dirs, files in os.walk(package.fakeroot_path):
for f in files:
new_dir = os.path.normpath(os.path.join(package.root, root[len(package.fakeroot_path) + 1:len(root)]))
src = os.path.join(root, f)
dest = os.path.join(new_dir, f)
if (os.path.islink(src)):
self.links.append([root, new_dir, f])
else:
self.files.append([src, dest])
for d in dirs:
self.dirs.append(os.path.join(package.root, root[len(package.fakeroot_path) + 1: len(root)], d))
def create_dirs(self):
# Go through self.dirs and check to see if a directory exists. If it does not, create it.
for d in self.dirs:
if not os.path.exists(d): # If the directory does not exist, run the equivalent of
os.makedirs(d) # mkdir -p on it.
io_output.vbprint(self.package.verbosity, 'DD {}'.format(d))
else:
io_output.vbprint(self.package.verbosity, 'UU {}'.format(d))
continue
def remove_dirs(self):
for d in reversed(self.dirs): # remove the directories that are the highest in the tree first.
if os.path.isdir(d): # If the directory exists
if not os.listdir(d): # and is empty...
os.rmdir(d) # remove it.
io_output.vbprint(self.package.verbosity, '-- {}'.format(d))
else: # If it is not empty.
io_output.vbprint(self.package.verbosity, 'UU {}'.format(d))
else: # If it does not exist.
io_output.vbprint(self.package.verbosity, '?? {}'.format(d))
def copy_files(self):
for f in self.files:
if os.path.exists(f[1]): # If the file exists, show that it is being used.
print 'Overwrite {}???'.format(f[1])
# TODO
# TODO: "Code" for overwiting stuff goes here.
# TODO: If yes, copy the file and add it to the DB.
# TODO: Perhaps an option to overwrite all files could be useful?
# TODO
continue
else: # If it does not exist,
try: # try...
shutil.copy2(f[0], f[1]) # copying it!
self.add_to_db(f)
io_output.vbprint(self.package.verbosity, '++ {}'.format(f[1]))
except:
io_output.vbprint(self.package.verbosity, 'Failed to copy a file...rolling back changes.')
#self.remove_files()
break
def remove_files(self):
for f in self.files:
if os.path.exists(f[1]):
os.remove(f[1])
self.remove_from_db(f)
io_output.vbprint(self.package.verbosity, '-- {}'.format(f[1]))
else:
io_output.vbprint(self.package.verbosity, '?? {}'.format(f[1]))
def create_links(self):
for l in self.links:
try:
if not os.path.exists(os.path.join(l[1], l[2])):
linkto = os.path.join(l[1], os.readlink(os.path.join(l[0], l[2])))
os.symlink(linkto, os.path.join(l[1], l[2]))
io_output.vbprint(self.package.verbosity, 'LL {}'.format(l[2]))
else:
print 'Overwrite existing link {}??'.format(l[2])
# TODO: See above todo for more info. ^^^^
except:
print 'Couldn\'t find the specified fakeroot!'
break
def remove_links(self):
for l in self.links:
try:
os.remove(os.path.join(l[1], l[2]))
io_output.vbprint(self.package.verbosity, '-- {}.'.format(l))
except:
raise OSError('\nFailed to remove the link `{}`'.format(os.path.join(l[1], l[2])))
def add_to_db(self, f):
"""Returns 0 if the db can't be read, 1 if the file is added."""
try:
self.package.db_cursor.execute('INSERT INTO Files VALUES(?, ?, ?, ?);', (f[1], md5_gen.generate(f[1]),
os.path.getsize(f[1]),
self.package.name))
return 1
except:
return 0
def remove_from_db(self, f):
self.package.db_cursor.execute('DELETE FROM Files WHERE Path=?;', (f[1],))对于这两个文件,我觉得我的设计有点拙劣。特别是,Package和Fakeroot对象的设计似乎很糟糕。此外,fakeroot.py中用于复制文件/删除文件的许多类似方法似乎有些多余。你认为如何?
def vbprint(verb_l, message):
"""Take a level of verboseness, `verb_l`, and a message to be printed. If verb_l > 0, the message is printed."""
if verb_l != 0:
print messagemd5_gen.py (这段代码的想法是通过搜索Google寻找类似于"md5 python“的东西找到的):
import hashlib
def generate(filename):
"""Return the md5 hash of filename.
Keyword arguments:
filename -- The path and name of the file to calculate the SHA1 hash of
"""
# Returns the md5 hash of the given file.
md5 = hashlib.md5()
with open(filename, 'rb') as file:
while True:
block = file.read(2**10)
if not block:
break
md5.update(block)
return md5.hexdigest()io_crate.py --用于从有关包的文件中获取信息:
from re import split
def read_crate(package):
"""Opens a crate file, reads the variables, and returns them as a sorted list of tuples.
Keyword arguments:
package -- A Package object, as defined in package.py
"""
# Returns 0 if the crate file cannot be read, 1 on success.
try:
crate_text = open(package).read()
except IOError:
print 'Failed to read the crate file {}.'.format(package.crate_path)
return 0
processed = split("=.*?\"|\".*?\n", crate_text)
lastline = ""
final = []
for line in processed:
if lastline.isupper():
if '_DEP' in lastline:
final.append((lastline, split(' ', line)))
else:
final.append((lastline, line))
lastline = line
return sorted(final, key=lambda pos: pos[0])DESCRIPTION=是“所有酒吧中最愚蠢的。”HOMEPAGE="http://www.foo.it/“REQUIRED_DEP="foobar-11-2”RECOMMENDED_DEP="foobus-1.7“”OPTIONAL_DEP=“foon-7.6a
发布于 2015-11-20 19:38:02
~/Documents/fakeroot。但是,我认为这是/tmp的重点,因为您应该希望在之后从系统中清除这些文件。verbosity和io_output可以用logging代替。io_crate应该添加到package.py中,而不是作为一个导入。except应该始终有你要防范的东西!如果您将^C从程序中删除,当它在尝试中时,它将继续执行。打印“无法读取数据库.”。它可以预防sys.exit。read_crate不应该抑制IOError。当您期望数组作为输出时,所实现的只是一个索引错误。还有令人困惑的回溯。close一个文件。一个简单的方法是使用with。打开(包)为f: f.read()*.crate,以使处理更容易。打开(包)为f: for行在f:.'=.*?"|".*?\n'更容易阅读。for line in processed的工作方式。这是没有意义的,因为你不一行行,你去关键字,价值,关键字,价值,.read_crate返回一个字典,因为这样它就更加可靠和可扩展。md5_sum.py应该添加到fakeroot.py中。如果package.py也应该这么做的话,这也是值得商榷的。这是个小程序..。md5_sum.py看上去不错。但md5不是sha1。Fakeroot可能只是我,但self.dirs是可怕的记忆饥饿。每个索引都有package.root + root[...],然后它的名称。我用发电机就行了。os.path.join(package.root, root[...])。把它存储在一个变量中。self.dirs制作了一个生成器,则不需要使用reversed。相反,将topdown=False传递给os.walk。purge函数。并在__init__或其他单个函数中执行“create”内容。# If it does not exist,和try: # try...都很糟糕。如果您询问任何程序员,以及相当多的非程序员,他们就会明白if not os.path.exists()意味着路径确实不存在。read_cratedef read_crate(path):
with open(path) as f:
return {
key: val
for key, val in (
line.split('=', 1)
for line in f
)
}这导致了在Package中的简单使用。
self.crate = io_crate.read_crate(self.crate_path)
self.description = self.crate['DESCRIPTION']purge.这应该是一个简单的反向os.walk。您不需要做更多的函数,因为它们将是1/2行。在算法中更容易读懂。
def purge(self):
for root, dirs, files in os.walk(package.root, topdown=False):
for name in files:
path = os.path.join(root, name)
try:
os.remove(path)
except ...:
logging.warn('-- ' + path)
else:
logging.info('-- ' + path)
if not os.path.islink(src):
self.remove_from_db(path)
for name in dirs:
path = os.path.join(root, name)
try:
os.rmdir(path)
except ...:
logging.warn('-- ' + path)
else:
logging.info('-- ' + path)注意使用python的记录器!这是个不错的工具。您甚至可以使用它将日志保存到文件中!
这与purge正好相反,所以,我建议您这样做。但是循环的第一个应该是package.root + root[...]。比如:
fakeroot_len = len(package.fakeroot_path) + 1
for root, dirs, files in os.walk(package.fakeroot_path):
fakeroot = os.path.join(package.root, root[fakeroot_len:len(root)])
for name in files:
...
for name in dirs:
...https://codereview.stackexchange.com/questions/111335
复制相似问题