• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package main
16
17import (
18	"archive/zip"
19	"flag"
20	"fmt"
21	"io"
22	"io/ioutil"
23	"log"
24	"os"
25	"path/filepath"
26	"strings"
27)
28
29var (
30	outputDir  = flag.String("d", "", "output dir")
31	outputFile = flag.String("l", "", "output list file")
32	filter     = flag.String("f", "", "optional filter pattern")
33)
34
35func must(err error) {
36	if err != nil {
37		log.Fatal(err)
38	}
39}
40
41func writeFile(filename string, in io.Reader, perm os.FileMode) error {
42	out, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
43	if err != nil {
44		return err
45	}
46	_, err = io.Copy(out, in)
47	if err != nil {
48		out.Close()
49		return err
50	}
51
52	return out.Close()
53}
54
55func main() {
56	flag.Usage = func() {
57		fmt.Fprintln(os.Stderr, "usage: zipsync -d <output dir> [-l <output file>] [-f <pattern>] [zip]...")
58		flag.PrintDefaults()
59	}
60
61	flag.Parse()
62
63	if *outputDir == "" {
64		flag.Usage()
65		os.Exit(1)
66	}
67
68	inputs := flag.Args()
69
70	// For now, just wipe the output directory and replace its contents with the zip files
71	// Eventually this could only modify the directory contents as necessary to bring it up
72	// to date with the zip files.
73	must(os.RemoveAll(*outputDir))
74
75	must(os.MkdirAll(*outputDir, 0777))
76
77	var files []string
78	seen := make(map[string]string)
79
80	for _, input := range inputs {
81		reader, err := zip.OpenReader(input)
82		if err != nil {
83			log.Fatal(err)
84		}
85		defer reader.Close()
86
87		for _, f := range reader.File {
88			if *filter != "" {
89				if match, err := filepath.Match(*filter, filepath.Base(f.Name)); err != nil {
90					log.Fatal(err)
91				} else if !match {
92					continue
93				}
94			}
95			if filepath.IsAbs(f.Name) {
96				log.Fatalf("%q in %q is an absolute path", f.Name, input)
97			}
98
99			if prev, exists := seen[f.Name]; exists {
100				log.Fatalf("%q found in both %q and %q", f.Name, prev, input)
101			}
102			seen[f.Name] = input
103
104			filename := filepath.Join(*outputDir, f.Name)
105			if f.FileInfo().IsDir() {
106				must(os.MkdirAll(filename, f.FileInfo().Mode()))
107			} else {
108				must(os.MkdirAll(filepath.Dir(filename), 0777))
109				in, err := f.Open()
110				if err != nil {
111					log.Fatal(err)
112				}
113				must(writeFile(filename, in, f.FileInfo().Mode()))
114				in.Close()
115				files = append(files, filename)
116			}
117		}
118	}
119
120	if *outputFile != "" {
121		data := strings.Join(files, "\n")
122		if len(files) > 0 {
123			data += "\n"
124		}
125		must(ioutil.WriteFile(*outputFile, []byte(data), 0666))
126	}
127}
128