2012-05-29 3 views
2

SCons предоставляет Zip-конструктор для создания zip-файлов из групп файлов. Например, предположим, что мы имеем папку foo, которая выглядит следующим образом:Как заставить SCons не включать базовый каталог в zip-файлы?

foo/ 
foo/blah.txt 

и создаем почтовый файл foo.zip из папки foo:

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

Это производит почтовый файл:

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

Однако предположим, что мы пользуемся баром VariantDir, который содержит foo:

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

Поскольку мы находимся в VariantDir, мы по-прежнему использовать ту же команду, чтобы создать файл почтового индекса, даже если он имеет несколько различных эффектов:

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

Это создает файл почтового индекса:

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

Проблема дополнительно bar/ префикс для каждого из файлов в пределах zip. Если это не было SCons, простым решением было бы cd в bar и вызвать zip изнутри там с чем-то вроде cd bar; zip -r foo.zip foo/. Однако это странно/сложно с помощью SCons, и, во всяком случае, кажется очень не-SCons-подобным. Есть ли лучшее решение?

ответ

5

Вы можете создать построитель SCons, который выполняет эту задачу. Мы можем использовать стандартный zip-файл Python для создания 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/') 
1

Каталоги действительно может быть проблемой с SCons. Есть несколько различных способов, вы можете указать каталог файлов включить в Zip (файл) следующим образом, предполагая, что файлы «в проекте»:

  1. по отношению к директории корня проекта, добавления префикса путь с '#'. Эта опция будет включать полный каталог, как вы упомянули
  2. относительно конкретного файла SConscript. Либо укажите файлы в том же каталоге, либо укажите подкаталог относительно SConscript.

Похоже, вы хотите второй вариант. У вас есть файл SConscript в том же каталоге, который вы хотите заархивировать, foo в вашем случае?Это должно работать даже для варианта_dir.

+0

Проблема не указав каталог почтовый файл, это каталог, который я хочу добавить ... И нет, у меня нет файла SConscript в каталог. Каталог создается при создании, а затем я хочу закрепить одну из созданных папок на месте. – Xymostech

+0

@ Xymostech, верно, я переформулировал ответ. Я понял, что вы ссылаетесь на файлы/dir, которые нужно добавить в zip. Вместо указания каталога вы можете использовать целевой объект, возвращенный из компоновщика. Если вы включите SConscript, я могу взглянуть. – Brady

+0

Я пытался использовать возврат от строителя, и это все еще не работает. Вот код: https://gist.github.com/2822868 – Xymostech

Смежные вопросы