... | ... |
@@ -56,6 +56,7 @@ func (srv *Server) Help() string { |
56 | 56 |
{"rm", "Remove a container"}, |
57 | 57 |
{"rmi", "Remove an image"}, |
58 | 58 |
{"run", "Run a command in a new container"}, |
59 |
+ {"search", "Search for an image in the docker index"} |
|
59 | 60 |
{"start", "Start a stopped container"}, |
60 | 61 |
{"stop", "Stop a running container"}, |
61 | 62 |
{"tag", "Tag an image into a repository"}, |
... | ... |
@@ -1001,6 +1002,34 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout rcli.DockerConn, args . |
1001 | 1001 |
return <-container.Attach(stdin, nil, stdout, stdout) |
1002 | 1002 |
} |
1003 | 1003 |
|
1004 |
+func (srv *Server) CmdSearch(stdin io.ReadCloser, stdout rcli.DockerConn, args ...string) error { |
|
1005 |
+ cmd := rcli.Subcmd(stdout, "search", "NAME", "Search the docker index for images") |
|
1006 |
+ if err := cmd.Parse(args); err != nil { |
|
1007 |
+ return nil |
|
1008 |
+ } |
|
1009 |
+ if cmd.NArg() != 1 { |
|
1010 |
+ cmd.Usage() |
|
1011 |
+ return nil |
|
1012 |
+ } |
|
1013 |
+ term := cmd.Arg(0) |
|
1014 |
+ results, err := srv.runtime.graph.SearchRepositories(stdout, term) |
|
1015 |
+ if err != nil { |
|
1016 |
+ return err |
|
1017 |
+ } |
|
1018 |
+ fmt.Fprintf(stdout, "Found %d results matching your query (\"%s\")\n", results.NumResults, results.Query) |
|
1019 |
+ w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0) |
|
1020 |
+ fmt.Fprintf(w, "NAME\tDESCRIPTION\n") |
|
1021 |
+ for _, repo := range results.Results { |
|
1022 |
+ description := repo["description"] |
|
1023 |
+ if len(description) > 45 { |
|
1024 |
+ description = Trunc(description, 42) + "..." |
|
1025 |
+ } |
|
1026 |
+ fmt.Fprintf(w, "%s\t%s\n", repo["name"], description) |
|
1027 |
+ } |
|
1028 |
+ w.Flush() |
|
1029 |
+ return nil |
|
1030 |
+} |
|
1031 |
+ |
|
1004 | 1032 |
// Ports type - Used to parse multiple -p flags |
1005 | 1033 |
type ports []int |
1006 | 1034 |
|
... | ... |
@@ -9,6 +9,7 @@ import ( |
9 | 9 |
"io" |
10 | 10 |
"io/ioutil" |
11 | 11 |
"net/http" |
12 |
+ "net/url" |
|
12 | 13 |
"path" |
13 | 14 |
"strings" |
14 | 15 |
) |
... | ... |
@@ -638,3 +639,33 @@ func (graph *Graph) Checksums(output io.Writer, repo Repository) ([]map[string]s |
638 | 638 |
} |
639 | 639 |
return result, nil |
640 | 640 |
} |
641 |
+ |
|
642 |
+type SearchResults struct { |
|
643 |
+ Query string `json:"query"` |
|
644 |
+ NumResults int `json:"num_results"` |
|
645 |
+ Results []map[string]string `json:"results"` |
|
646 |
+} |
|
647 |
+ |
|
648 |
+func (graph *Graph) SearchRepositories(stdout io.Writer, term string) (*SearchResults, error) { |
|
649 |
+ client := graph.getHttpClient() |
|
650 |
+ u := INDEX_ENDPOINT + "/search?q=" + url.QueryEscape(term) |
|
651 |
+ req, err := http.NewRequest("GET", u, nil) |
|
652 |
+ if err != nil { |
|
653 |
+ return nil, err |
|
654 |
+ } |
|
655 |
+ res, err := client.Do(req) |
|
656 |
+ if err != nil { |
|
657 |
+ return nil, err |
|
658 |
+ } |
|
659 |
+ defer res.Body.Close() |
|
660 |
+ if res.StatusCode != 200 { |
|
661 |
+ return nil, fmt.Errorf("Unexepected status code %d", res.StatusCode) |
|
662 |
+ } |
|
663 |
+ rawData, err := ioutil.ReadAll(res.Body) |
|
664 |
+ if err != nil { |
|
665 |
+ return nil, err |
|
666 |
+ } |
|
667 |
+ result := new(SearchResults) |
|
668 |
+ err = json.Unmarshal(rawData, result) |
|
669 |
+ return result, err |
|
670 |
+} |