Golang程序  |  129行  |  3.03 KB

// Copyright 2016 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"strings"

	"android/soong/third_party/zip"
)

var (
	input  = flag.String("i", "", "zip file to read from")
	output = flag.String("o", "", "output file")
)

func usage() {
	fmt.Fprintln(os.Stderr, "usage: zip2zip -i zipfile -o zipfile [filespec]...")
	flag.PrintDefaults()
	fmt.Fprintln(os.Stderr, "  filespec:")
	fmt.Fprintln(os.Stderr, "    <name>")
	fmt.Fprintln(os.Stderr, "    <in_name>:<out_name>")
	fmt.Fprintln(os.Stderr, "    <glob>:<out_dir>/")
	fmt.Fprintln(os.Stderr, "")
	fmt.Fprintln(os.Stderr, "Files will be copied with their existing compression from the input zipfile to")
	fmt.Fprintln(os.Stderr, "the output zipfile, in the order of filespec arguments")
	os.Exit(2)
}

func main() {
	flag.Parse()

	if flag.NArg() == 0 || *input == "" || *output == "" {
		usage()
	}

	reader, err := zip.OpenReader(*input)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(3)
	}
	defer reader.Close()

	output, err := os.Create(*output)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(4)
	}
	defer output.Close()

	writer := zip.NewWriter(output)
	defer func() {
		err := writer.Close()
		if err != nil {
			fmt.Fprintln(os.Stderr, err)
			os.Exit(5)
		}
	}()

	for _, arg := range flag.Args() {
		var input string
		var output string

		// Reserve escaping for future implementation, so make sure no
		// one is using \ and expecting a certain behavior.
		if strings.Contains(arg, "\\") {
			fmt.Fprintln(os.Stderr, "\\ characters are not currently supported")
			os.Exit(6)
		}

		args := strings.SplitN(arg, ":", 2)
		input = args[0]
		if len(args) == 2 {
			output = args[1]
		}

		if strings.IndexAny(input, "*?[") >= 0 {
			for _, file := range reader.File {
				if match, err := filepath.Match(input, file.Name); err != nil {
					fmt.Fprintln(os.Stderr, err)
					os.Exit(7)
				} else if match {
					var newFileName string
					if output == "" {
						newFileName = file.Name
					} else {
						_, name := filepath.Split(file.Name)
						newFileName = filepath.Join(output, name)
					}
					err = writer.CopyFrom(file, newFileName)
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
						os.Exit(8)
					}
				}
			}
		} else {
			if output == "" {
				output = input
			}
			for _, file := range reader.File {
				if input == file.Name {
					err = writer.CopyFrom(file, output)
					if err != nil {
						fmt.Fprintln(os.Stderr, err)
						os.Exit(8)
					}
					break
				}
			}
		}
	}
}