| // Utility to generate web extension manifest files from GJSON (Generic JSON) |
| // templates, given some dependencies. |
| package main |
| |
| import ( |
| "bufio" |
| "flag" |
| "fmt" |
| "io" |
| "log" |
| "os" |
| "regexp" |
| "strings" |
| ) |
| |
| var beginningOfIfStatement = regexp.MustCompile(`^\s*#if defined\(([^\(\)]*)\)\s*$`) |
| var endOfIfStatement = regexp.MustCompile(`^\s*#endif\s*$`) |
| |
| var ( |
| quietMode = flag.Bool("quiet", false, "Quiet mode") |
| templateFile = flag.String("template", "", "Template file") |
| destFile = flag.String("dest", "", "Destination file") |
| ) |
| |
| // findWithCaseFolding returns whether there is some element of slice which is |
| // equal to val under Unicode case-folding. |
| func findWithCaseFolding(slice []string, val string) bool { |
| for _, item := range slice { |
| if strings.EqualFold(item, val) { |
| return true |
| } |
| } |
| return false |
| } |
| |
| // Given a Generic JSON (GJSON) template and the dependencies met, |
| // WriteManifest will write at dest the manifest file generated from the |
| // template according to the dependencies. |
| func WriteManifest(template io.Reader, dest io.Writer, dependencies []string) error { |
| level := 0 |
| activeLevel := 0 |
| scanner := bufio.NewScanner(template) |
| for scanner.Scan() { |
| line := scanner.Text() |
| considerLine := false |
| if m := beginningOfIfStatement.FindStringSubmatch(line); m != nil { |
| if level == activeLevel { |
| statementDeps := m[1] |
| deps := strings.Split(statementDeps, "||") |
| for _, dep := range deps { |
| dep = strings.TrimSpace(dep) |
| if findWithCaseFolding(dependencies, dep) { |
| activeLevel++ |
| break |
| } |
| } |
| } |
| level++ |
| } else if m := endOfIfStatement.MatchString(line); m { |
| if activeLevel == level { |
| activeLevel-- |
| } |
| level-- |
| } else { |
| considerLine = level == activeLevel |
| } |
| |
| if considerLine { |
| _, err := io.WriteString(dest, line+"\n") |
| if err != nil { |
| return fmt.Errorf("Can't write manifest: %v", err) |
| } |
| } |
| } |
| |
| return nil |
| } |
| |
| // WriteManifestFileNames is the same as WriteManifest, but instead of receiving |
| // read and write handlers for each file, this function receives the file names |
| // as strings and reads/writes from/to those files. |
| func WriteManifestFileNames(templateFile string, destFile string, dependencies []string) error { |
| template, err := os.Open(templateFile) |
| if err != nil { |
| return fmt.Errorf("Couldn't open file %v: %v", templateFile, err) |
| } |
| defer template.Close() |
| |
| dest, err := os.Create(destFile) |
| if err != nil { |
| return fmt.Errorf("Couldn't create file %v: %v", destFile, err) |
| } |
| defer dest.Close() |
| |
| return WriteManifest(template, dest, dependencies) |
| } |
| |
| func main() { |
| log.SetPrefix("generatemanifest: ") |
| log.SetFlags(0) |
| |
| flag.Parse() |
| dependencies := flag.Args() |
| |
| if len(dependencies) == 0 { |
| log.Fatalf("Pass the dependencies as arguments (for instance, run `go run generateManifest.go CHROMIUM`).") |
| } |
| if *templateFile == "" { |
| log.Fatalf("Pass the template file name via the -template flag.") |
| } |
| if *destFile == "" { |
| log.Fatalf("Pass the destination file name via the -dest flag.") |
| } |
| |
| err := WriteManifestFileNames(*templateFile, *destFile, dependencies) |
| if err != nil { |
| log.Fatalf("%v", err) |
| } else if !*quietMode { |
| log.Println("Manifest has been generated successfully") |
| } |
| } |