// Copyright 2020 Google LLC // // 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 // // https://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 client import ( "fmt" "android.googlesource.com/platform/tools/treble.git/hacksaw/bind" "android.googlesource.com/platform/tools/treble.git/hacksaw/codebase" "android.googlesource.com/platform/tools/treble.git/hacksaw/workspace" ) const usage = `Usage: hacksaw Commands: help: show this message codebase add : Add codebase to hacksaw's list. codebase list: List all codebases that hacksaw knows about. codebase default : Change the default codebase. codebase remove : Remove a codebase from hacksaw's list. workspace new : Create a new workspace from a codebase. The codebase is optional if a default codebase has already been set. workspace recreate : Recreate an existing workspace. This will recreate any read-only bind mounts which may be necessary when a machine is rebooted. workspace list: List all known workspaces. workspace remove : Remove a workspace. edit : Make a workspace path editable by checking out the parent git project.` type Command struct { workspace workspace.Workspace } func NewCommand(bm bind.PathBinder, wtd string) Command { return Command{workspace.New(bm, wtd)} } func (c Command) addCodebase(args []string) error { if len(args) < 5 { return fmt.Errorf("Codebase name and path are required\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } name := args[3] path := args[4] _, err := codebase.Add(name, path) if err != nil { return err } fmt.Println("Added codebase", name) return err } func (c Command) defaultCodebase(args []string) error { if len(args) < 4 { return fmt.Errorf("Codebase name is required\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } name := args[3] if err := codebase.SetDefault(name); err != nil { return err } fmt.Println("Default codebase set to", name) return nil } func (c Command) listCodebases() { def := codebase.Default() if def == "" { def = "None" } fmt.Println("Default codebase:") fmt.Println("\t", def) list := codebase.List() fmt.Println("Codebases:") for name, path := range list { fmt.Println("\t", name, path) } } func (c Command) removeCodebase(args []string) error { if len(args) < 4 { return fmt.Errorf("Codebase name required\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } name := args[3] _, err := codebase.Remove(name) if err != nil { return err } fmt.Println("Removed codebase", name) return nil } func (c Command) createWorkspace(args []string) error { var codebaseName string defaultCodebase := codebase.Default() switch len(args) { case 4: if defaultCodebase == "" { return fmt.Errorf("Codebase name is required\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } else { codebaseName = defaultCodebase } case 5: codebaseName = args[4] default: return fmt.Errorf("Unexpected number of arguments\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } workspaceName := args[3] dir, err := c.workspace.Create(workspaceName, codebaseName) if err != nil { return err } fmt.Println("Created", workspaceName, "at", dir) return nil } func (c Command) recreateWorkspace(args []string) error { if len(args) < 4 { return fmt.Errorf("Workspace name is required\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } workspaceName := args[3] dir, err := c.workspace.Recreate(workspaceName) if err != nil { return err } fmt.Println("Recreated", workspaceName, "at", dir) return nil } func (c Command) listWorkspaces() { list := c.workspace.List() fmt.Println("Workspaces:") for name, codebase := range list { fmt.Println("\t", name, codebase) } } func (c Command) removeWorkspace(args []string) error { if len(args) < 4 { return fmt.Errorf("Workspace name required\n"+ "Usage: %s %s %s ", args[0], args[1], args[2]) } name := args[3] _, err := c.workspace.Remove(name) if err != nil { return err } fmt.Println("Removed workspace", name) return nil } func (c Command) editProject(args []string) error { if len(args) < 3 { return fmt.Errorf("Edit path required\n"+ "Usage: %s %s ", args[0], args[1]) } path := args[2] branchName, projectPath, err := c.workspace.Edit(path) if err != nil { return err } fmt.Printf("Created branch %s on project %s\n", branchName, projectPath) return nil } //Handle parses all command line arguments func (c Command) Handle(args []string) error { if len(args) < 2 || args[1] == "help" { fmt.Println(usage) return nil } command := args[1] switch command { case "codebase", "cb": if len(args) < 3 { return fmt.Errorf("Not enough arguments for codebase command") } subcommand := args[2] switch subcommand { case "add": return c.addCodebase(args) case "remove", "rm": return c.removeCodebase(args) case "default", "def": return c.defaultCodebase(args) case "list", "ls": c.listCodebases() return nil default: return fmt.Errorf("Command \"%s %s\" not found", command, subcommand) } case "workspace", "ws": if len(args) < 3 { return fmt.Errorf("Not enough arguments for workspace command") } subcommand := args[2] switch subcommand { case "new": return c.createWorkspace(args) case "recreate": return c.recreateWorkspace(args) case "remove", "rm": return c.removeWorkspace(args) case "list", "ls": c.listWorkspaces() return nil default: return fmt.Errorf("Command \"%s %s\" not found", command, subcommand) } case "edit": return c.editProject(args) default: return fmt.Errorf("Command \"%s\" not found", command) } return nil }