3

SCons 提供了一个 Zip 构建器来从文件组生成 zip 文件。例如,假设我们有一个foo如下所示的文件夹:

foo/
foo/blah.txt

foo.zip我们从一个文件夹创建 zip 文件foo

env.Zip('foo.zip', 'foo/')

这会生成一个 zip 文件:

$ unzip -l foo.zip
Archive:  foo.zip
  foo/
  foo/foo.txt

然而,假设我们使用了一个VariantDir包含 foo 的 of bar:

bar/
bar/foo/
bar/foo/foo.txt

因为我们在 a 中VariantDir,所以我们仍然使用相同的命令来创建 zip 文件,尽管它的效果略有不同:

env.Zip('foo.zip', 'foo/')

这会生成 zip 文件:

$ unzip -l bar/foo.zip
Archive:  bar/foo.zip
  bar/foo/
  bar/foo/foo.txt

问题是 zip 中每个文件的额外bar/前缀。如果这不是 SCons,简单的解决方案是 cd 进入bar并从那里调用 zip 之类的东西cd bar; zip -r foo.zip foo/。然而,这对于 SCons 来说很奇怪/困难,而且无论如何看起来非常不像 SCons。有更好的解决方案吗?

4

3 回答 3

5

您可以创建一个 SCons Builder 来完成此任务。我们可以使用标准的 Python zipfile 来制作 zip 文件。我们利用zipfile.write,它允许我们指定要添加的文件,以及在 zip 中应该调用的文件:

zf.write('foo/bar', 'bar') # save foo/bar as bar

为了获得正确的路径,我们使用os.path.relpath基础文件的路径来查找整个文件的路径。

最后,我们使用os.walk遍历要添加的目录的内容,并调用前面的两个函数将它们正确地添加到最终的 zip 中。

import os.path
import zipfile

def zipbetter(target, source, env):
    # Open the zip file with appending, so multiple calls will add more files
    zf = zipfile.ZipFile(str(target[0]), 'a', zipfile.ZIP_DEFLATED)
    for s in source:
        # Find the path of the base file
        basedir = os.path.dirname(str(s))
        if s.isdir():
            # If the source is a directory, walk through its files
            for dirpath, dirnames, filenames in os.walk(str(s)):
                for fname in filenames:
                    path = os.path.join(dirpath, fname)
                    if os.path.isfile(path):
                        # If this is a file, write it with its relative path
                        zf.write(path, os.path.relpath(path, basedir))
        else:
            # Otherwise, just write it to the file
            flatname = os.path.basename(str(s))
            zf.write(str(s), flatname)
    zf.close()

# Make a builder using the zipbetter function, that takes SCons files
zipbetter_bld = Builder(action = zipbetter,
                        target_factory = SCons.Node.FS.default_fs.Entry,
                        source_factory = SCons.Node.FS.default_fs.Entry)

# Add the builder to the environment
env.Append(BUILDERS = {'ZipBetter' : zipbetter_bld})

像普通的 SCons 一样调用它Zip

env.ZipBetter('foo.zip', 'foo/')
于 2012-05-29T04:56:43.480 回答
1

对于 SCons,目录确实是一个挑战。假设文件在“项目中”,有几种不同的方法可以指定要包含在 Zip() 文件中的文件目录,如下所示:

  1. 相对于根项目目录,在路径前加上“#”。这个选项将包括完整的目录,就像你提到的
  2. 相对于特定的 SConscript 文件。要么指定同一目录中的文件,要么指定相对于 SConscript 的子目录。

听起来你想要第二个选项。在您的情况下,您是否在要压缩的同一目录中有一个 SConscript 文件foo?这甚至适用于 variant_dir。

于 2012-05-29T05:27:42.437 回答
1

使用构造变量'ZIPROOT'</p>

于 2016-12-15T05:45:42.147 回答