Python 如何使SCON在zip文件中不包含基本目录?

Python 如何使SCON在zip文件中不包含基本目录?,python,zip,scons,Python,Zip,Scons,SCons提供了一个Zip生成器,用于从文件组生成Zip文件。 例如,假设我们有一个文件夹foo,如下所示: foo/ foo/blah.txt 我们从文件夹foo创建zip文件foo.zip: env.Zip('foo.zip', 'foo/') 这将生成一个zip文件: $ unzip -l foo.zip Archive: foo.zip foo/ foo/foo.txt $ unzip -l bar/foo.zip Archive: bar/foo.zip bar/

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

foo/
foo/blah.txt
我们从文件夹
foo
创建zip文件
foo.zip

env.Zip('foo.zip', 'foo/')
这将生成一个zip文件:

$ unzip -l foo.zip
Archive:  foo.zip
  foo/
  foo/foo.txt
$ unzip -l bar/foo.zip
Archive:  bar/foo.zip
  bar/foo/
  bar/foo/foo.txt
但是,假设我们使用的是一个包含foo的bar的
VariantDir

bar/
bar/foo/
bar/foo/foo.txt
由于我们使用的是
VariantDir
,因此我们仍然使用相同的命令来创建zip文件,尽管它的效果略有不同:

env.Zip('foo.zip', 'foo/')
这将生成zip文件:

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

问题是zip中的每个文件都有额外的
bar/
前缀。如果不是SCons,那么简单的解决方案是将cd放入
bar
,然后从里面用类似
cd bar的东西调用zip;zip-r foo.zip foo/
。然而,这对司康人来说是很奇怪/困难的,而且至少看起来很不像司康人。有更好的解决方案吗?

您可以创建一个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})
就像普通烤饼一样叫它
Zip

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

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

  • 相对于根项目目录,在路径前面加上“#”。此选项将包括完整的目录,如您所述
  • 相对于特定的SConscript文件。指定同一目录中的文件,或指定相对于SConscript的子目录

  • 听起来你想要第二个选择。在您的案例中,
    foo
    中是否有与您要压缩的目录相同的SConscript文件?即使对于variant_dir,这也应该有效。

    使用构造变量“ZIPROOT”

    问题不是指定zip文件的目录,而是我要添加的目录。。。不,我在目录中没有SConscript文件。生成时正在创建目录,然后我想将其中一个创建的文件夹压缩到位。@Xymostech,对,我重新编写了答案。我知道您指的是要添加到zip的文件/dir。您可以使用从生成器返回的目标,而不是指定目录。如果您包含SConscript,我可以看一看。我已经尝试使用生成器的返回,但仍然不起作用。代码如下:@Xymostech,您还可以使用Package()生成器,将PACKAGETYPE设置为zip。我会测试一下,看看是否有用。@Xymostech,顺便说一句,你住在我最喜欢的城市:)我以前住在路易斯维尔,但因为家庭原因不得不搬家。