Fan

 

class

build::CreateZip

sys::Obj
  build::Task
    build::CreateZip
//
// Copyright (c) 2008, Brian Frank and Andy Frank
// Licensed under the Academic Free License version 3.0
//
// History:
//   30 Sep 08  Brian Frank  Creation
//

**
** CreateZip is used to create a zip file from a directory on the file system.
**
class CreateZip : Task
{

  new make(BuildScript script)
    : super(script)
  {
    this.filter  = |File f->Bool| { return true }
  }

  override Void run()
  {
    // basic sanity checking
    if ((Obj?)inDir == null) throw fatal("Not configured: CreateZip.inDir")
    if ((Obj?)outFile == null) throw fatal("Not configured: CreateZip.outFile")
    if (!inDir.isDir) throw fatal("Not a directory: $inDir")

    // ensure outFile is not under inDir (although we do allow
    // outFile to be placed directly under inDir as convenience)
    inPath := inDir.normalize.pathStr
    outPath := outFile.normalize.parent.pathStr
    if (outPath.startsWith(inPath) && inPath != outPath)
      throw fatal("Cannot set outFile under inDir: $outPath under $inPath")

    // zip it!
    log.info("CreateZip [$outFile]")
    out := Zip.write(outFile.out)
    try
    {
      inDir.list.each |File f|
      {
        if (f.name == outFile.name) return
        zip(out, f, f.name)
      }
    }
    catch (Err err)
    {
      throw fatal("Cannot create zip [$outFile]", err)
    }
    finally
    {
      out.close
    }
  }

  private Void zip(Zip out, File f, Str path)
  {
    if (!filter.call2(f, path)) return
    if (f.isDir)
    {
      f.list.each |File sub|
      {
        zip(out, sub, path + "/" + sub.name)
      }
    }
    else
    {
      o := out.writeNext(path.toUri, f.modified)
      f.in.pipe(o)
      o.close
    }
  }

  ** Output zip file to create
  File outFile

  ** Directory to zip up.  The contents of this dir are recursively
  ** zipped up with zip paths relative to this root directory.
  File inDir

  ** This function is called on each file under 'inDir'; if true
  ** returned it is included in the zip, if false then it is excluded.
  ** Returning false for a directory will skip recursing the entire
  ** directory.
  |File f, Str path->Bool| filter
}