• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2020 Google LLC
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
15package client
16
17import (
18	"fmt"
19
20	"android.googlesource.com/platform/tools/treble.git/hacksaw/bind"
21	"android.googlesource.com/platform/tools/treble.git/hacksaw/codebase"
22	"android.googlesource.com/platform/tools/treble.git/hacksaw/workspace"
23)
24
25const usage = `Usage: hacksaw <command> <options>
26
27Commands:
28	help: show this message
29	codebase add <name> <path>: Add codebase to hacksaw's list.
30	codebase list: List all codebases that hacksaw knows about.
31	codebase default <name>: Change the default codebase.
32	codebase remove <name>: Remove a codebase from hacksaw's list.
33	workspace new <workspace_name> <codebase_name>: Create a new workspace
34	  from a codebase. The codebase is optional if a default codebase
35	  has already been set.
36	workspace recreate <name>: Recreate an existing workspace.
37	  This will recreate any read-only bind mounts which may be necessary
38	  when a machine is rebooted.
39	workspace list: List all known workspaces.
40	workspace remove <name>: Remove a workspace.
41	edit <path>: Make a workspace path editable by checking out the parent git project.`
42
43type Command struct {
44	workspace workspace.Workspace
45}
46
47func NewCommand(bm bind.PathBinder, wtd string) Command {
48	return Command{workspace.New(bm, wtd)}
49}
50
51func (c Command) addCodebase(args []string) error {
52	if len(args) < 5 {
53		return fmt.Errorf("Codebase name and path are required\n"+
54			"Usage: %s %s %s <codebase_name> <path>",
55			args[0], args[1], args[2])
56	}
57	name := args[3]
58	path := args[4]
59	_, err := codebase.Add(name, path)
60	if err != nil {
61		return err
62	}
63	fmt.Println("Added codebase", name)
64	return err
65}
66
67func (c Command) defaultCodebase(args []string) error {
68	if len(args) < 4 {
69		return fmt.Errorf("Codebase name is required\n"+
70			"Usage: %s %s %s <codebase_name>",
71			args[0], args[1], args[2])
72	}
73	name := args[3]
74	if err := codebase.SetDefault(name); err != nil {
75		return err
76	}
77	fmt.Println("Default codebase set to", name)
78	return nil
79}
80
81func (c Command) listCodebases() {
82	def := codebase.Default()
83	if def == "" {
84		def = "None"
85	}
86	fmt.Println("Default codebase:")
87	fmt.Println("\t", def)
88
89	list := codebase.List()
90	fmt.Println("Codebases:")
91	for name, path := range list {
92		fmt.Println("\t", name, path)
93	}
94}
95
96func (c Command) removeCodebase(args []string) error {
97	if len(args) < 4 {
98		return fmt.Errorf("Codebase name required\n"+
99			"Usage: %s %s %s <codebase>",
100			args[0], args[1], args[2])
101	}
102	name := args[3]
103	_, err := codebase.Remove(name)
104	if err != nil {
105		return err
106	}
107	fmt.Println("Removed codebase", name)
108	return nil
109}
110
111func (c Command) createWorkspace(args []string) error {
112	var codebaseName string
113	defaultCodebase := codebase.Default()
114	switch len(args) {
115	case 4:
116		if defaultCodebase == "" {
117			return fmt.Errorf("Codebase name is required\n"+
118				"Usage: %s %s %s <name> <codebase>",
119				args[0], args[1], args[2])
120		} else {
121			codebaseName = defaultCodebase
122		}
123	case 5:
124		codebaseName = args[4]
125	default:
126		return fmt.Errorf("Unexpected number of arguments\n"+
127			"Usage: %s %s %s <name> <codebase>",
128			args[0], args[1], args[2])
129	}
130
131	workspaceName := args[3]
132	dir, err := c.workspace.Create(workspaceName, codebaseName)
133	if err != nil {
134		return err
135	}
136	fmt.Println("Created", workspaceName, "at", dir)
137	return nil
138}
139
140func (c Command) recreateWorkspace(args []string) error {
141	if len(args) < 4 {
142		return fmt.Errorf("Workspace name is required\n"+
143			"Usage: %s %s %s <name>",
144			args[0], args[1], args[2])
145	}
146
147	workspaceName := args[3]
148	dir, err := c.workspace.Recreate(workspaceName)
149	if err != nil {
150		return err
151	}
152	fmt.Println("Recreated", workspaceName, "at", dir)
153	return nil
154}
155
156func (c Command) listWorkspaces() {
157	list := c.workspace.List()
158	fmt.Println("Workspaces:")
159	for name, codebase := range list {
160		fmt.Println("\t", name, codebase)
161	}
162}
163
164func (c Command) removeWorkspace(args []string) error {
165	if len(args) < 4 {
166		return fmt.Errorf("Workspace name required\n"+
167			"Usage: %s %s %s <name>",
168			args[0], args[1], args[2])
169	}
170	name := args[3]
171	_, err := c.workspace.Remove(name)
172	if err != nil {
173		return err
174	}
175	fmt.Println("Removed workspace", name)
176	return nil
177}
178
179func (c Command) editProject(args []string) error {
180	if len(args) < 3 {
181		return fmt.Errorf("Edit path required\n"+
182			"Usage: %s %s <path>",
183			args[0], args[1])
184	}
185	path := args[2]
186	branchName, projectPath, err := c.workspace.Edit(path)
187	if err != nil {
188		return err
189	}
190	fmt.Printf("Created branch %s on project %s\n",
191		branchName, projectPath)
192	return nil
193}
194
195//Handle parses all command line arguments
196func (c Command) Handle(args []string) error {
197	if len(args) < 2 || args[1] == "help" {
198		fmt.Println(usage)
199		return nil
200	}
201
202	command := args[1]
203
204	switch command {
205	case "codebase", "cb":
206		if len(args) < 3 {
207			return fmt.Errorf("Not enough arguments for codebase command")
208		}
209		subcommand := args[2]
210		switch subcommand {
211		case "add":
212			return c.addCodebase(args)
213		case "remove", "rm":
214			return c.removeCodebase(args)
215		case "default", "def":
216			return c.defaultCodebase(args)
217		case "list", "ls":
218			c.listCodebases()
219			return nil
220		default:
221			return fmt.Errorf("Command \"%s %s\" not found", command, subcommand)
222		}
223	case "workspace", "ws":
224		if len(args) < 3 {
225			return fmt.Errorf("Not enough arguments for workspace command")
226		}
227		subcommand := args[2]
228		switch subcommand {
229		case "new":
230			return c.createWorkspace(args)
231		case "recreate":
232			return c.recreateWorkspace(args)
233		case "remove", "rm":
234			return c.removeWorkspace(args)
235		case "list", "ls":
236			c.listWorkspaces()
237			return nil
238		default:
239			return fmt.Errorf("Command \"%s %s\" not found", command, subcommand)
240		}
241	case "edit":
242		return c.editProject(args)
243	default:
244		return fmt.Errorf("Command \"%s\" not found", command)
245	}
246	return nil
247}
248