• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2017 The Wuffs Authors.
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//    https://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
15// wuffs is a tool for managing Wuffs source code.
16package main
17
18import (
19	"bytes"
20	"flag"
21	"fmt"
22	"io/ioutil"
23	"os"
24	"path/filepath"
25	"sort"
26	"strings"
27
28	"github.com/google/wuffs/lang/wuffsroot"
29)
30
31var commands = []struct {
32	name string
33	do   func(wuffsRoot string, args []string) error
34}{
35	{"bench", doBench},
36	{"gen", doGen},
37	{"genlib", doGenlib},
38	{"test", doTest},
39}
40
41func usage() {
42	fmt.Fprintf(os.Stderr, `Wuffs is a tool for managing Wuffs source code.
43
44Usage:
45
46	wuffs command [arguments]
47
48The commands are:
49
50	bench   benchmark packages
51	gen     generate code for packages and dependencies
52	genlib  generate software libraries
53	test    test packages
54`)
55}
56
57func main() {
58	if err := main1(); err != nil {
59		os.Stderr.WriteString(err.Error() + "\n")
60		os.Exit(1)
61	}
62}
63
64func main1() error {
65	flag.Usage = usage
66	flag.Parse()
67
68	wuffsRoot, err := wuffsroot.Value()
69	if err != nil {
70		return err
71	}
72	if args := flag.Args(); len(args) > 0 {
73		for _, c := range commands {
74			if args[0] == c.name {
75				return c.do(wuffsRoot, args[1:])
76			}
77		}
78	}
79	usage()
80	os.Exit(1)
81	return nil
82}
83
84func findFiles(qualDirname string, suffix string) (filenames []string, err error) {
85	filenames, err = findFiles1(nil, qualDirname, suffix)
86	if err != nil {
87		return nil, err
88	}
89	sort.Strings(filenames)
90	return filenames, nil
91}
92
93func findFiles1(dstQF []string, qualDirname string, suffix string) (qualFilenames []string, err error) {
94	dstQF, relDirnames, err := appendDir(dstQF, qualDirname, suffix, true)
95	if err != nil {
96		return nil, err
97	}
98	for _, d := range relDirnames {
99		dstQF, err = findFiles1(dstQF, filepath.Join(qualDirname, d), suffix)
100		if err != nil {
101			return nil, err
102		}
103	}
104	return dstQF, nil
105}
106
107func listDir(qualDirname string, suffix string, returnSubdirs bool) (qualFilenames []string, relDirnames []string, err error) {
108	qualFilenames, relDirnames, err = appendDir(nil, qualDirname, suffix, returnSubdirs)
109	if err != nil {
110		return nil, nil, err
111	}
112	sort.Strings(qualFilenames)
113	sort.Strings(relDirnames)
114	return qualFilenames, relDirnames, nil
115}
116
117func appendDir(dstQF []string, qualDirname string, suffix string, returnSubdirs bool) (qualFilenames []string, relDirnames []string, err error) {
118	f, err := os.Open(qualDirname)
119	if err != nil {
120		return nil, nil, err
121	}
122	defer f.Close()
123
124	infos, err := f.Readdir(-1)
125	if err != nil {
126		return nil, nil, err
127	}
128	for _, o := range infos {
129		name := o.Name()
130		if o.IsDir() {
131			if returnSubdirs {
132				relDirnames = append(relDirnames, name)
133			}
134		} else if strings.HasSuffix(name, suffix) {
135			dstQF = append(dstQF, filepath.Join(qualDirname, name))
136		}
137	}
138
139	return dstQF, relDirnames, nil
140}
141
142func writeFile(filename string, contents []byte) error {
143	if existing, err := ioutil.ReadFile(filename); err == nil && bytes.Equal(existing, contents) {
144		fmt.Println("gen unchanged: ", filename)
145		return nil
146	}
147	if err := os.MkdirAll(filepath.Dir(filename), 0755); err != nil {
148		return err
149	}
150	if err := ioutil.WriteFile(filename, contents, 0644); err != nil {
151		return err
152	}
153	fmt.Println("gen wrote:     ", filename)
154	return nil
155}
156
157const (
158	langsDefault = "c"
159	langsUsage   = `comma-separated list of target languages (file extensions), e.g. "c,go,rs"`
160
161	skipgenDefault = false
162	skipgenUsage   = `whether to skip automatically generating code when testing`
163
164	skipgendepsDefault = false
165	skipgendepsUsage   = `whether to skip automatically generating packages' dependencies`
166)
167
168func parseLangs(commaSeparated string) ([]string, error) {
169	ret := []string(nil)
170	for _, s := range strings.Split(commaSeparated, ",") {
171		if !validName(s) {
172			return nil, fmt.Errorf(`invalid lang %q, not in [a-z0-9]+`, s)
173		}
174		ret = append(ret, s)
175	}
176	return ret, nil
177}
178
179func validName(s string) bool {
180	if len(s) == 0 {
181		return false
182	}
183	for _, c := range s {
184		if (c < '0' || '9' < c) && (c < 'a' || 'z' < c) {
185			return false
186		}
187	}
188	return true
189}
190