🌐 AI搜索 & 代理 主页
blob: 5bc2978e090fef18d11bc29484ac18235de38ecc [file] [log] [blame]
Solomon Hykesef711962013-03-22 00:47:231package docker
Solomon Hykes680f40c2013-03-21 19:18:472
3import (
4 "encoding/json"
Solomon Hykes49a78922013-03-22 03:06:205 "fmt"
Guillaume J. Charmes2e69e172013-05-14 22:37:356 "github.com/dotcloud/docker/utils"
Solomon Hykes680f40c2013-03-21 19:18:477 "io/ioutil"
Solomon Hykesd0c77652013-03-22 02:00:438 "os"
Solomon Hykes680f40c2013-03-21 19:18:479 "path/filepath"
Solomon Hykes846a9e82013-03-26 22:30:1610 "sort"
Solomon Hykes49a78922013-03-22 03:06:2011 "strings"
Solomon Hykes680f40c2013-03-21 19:18:4712)
13
Solomon Hykes640026e2013-03-22 23:07:1314const DEFAULT_TAG = "latest"
15
Solomon Hykes44faa072013-03-22 00:35:4916type TagStore struct {
Solomon Hykes680f40c2013-03-21 19:18:4717 path string
18 graph *Graph
Solomon Hykes44faa072013-03-22 00:35:4919 Repositories map[string]Repository
Solomon Hykes680f40c2013-03-21 19:18:4720}
21
Solomon Hykes44faa072013-03-22 00:35:4922type Repository map[string]string
Solomon Hykes680f40c2013-03-21 19:18:4723
Solomon Hykes44faa072013-03-22 00:35:4924func NewTagStore(path string, graph *Graph) (*TagStore, error) {
Solomon Hykes680f40c2013-03-21 19:18:4725 abspath, err := filepath.Abs(path)
26 if err != nil {
27 return nil, err
28 }
Solomon Hykes44faa072013-03-22 00:35:4929 store := &TagStore{
Solomon Hykes680f40c2013-03-21 19:18:4730 path: abspath,
31 graph: graph,
Solomon Hykes44faa072013-03-22 00:35:4932 Repositories: make(map[string]Repository),
Solomon Hykes680f40c2013-03-21 19:18:4733 }
Solomon Hykesd0c77652013-03-22 02:00:4334 // Load the json file if it exists, otherwise create it.
35 if err := store.Reload(); os.IsNotExist(err) {
36 if err := store.Save(); err != nil {
37 return nil, err
38 }
39 } else if err != nil {
Solomon Hykes680f40c2013-03-21 19:18:4740 return nil, err
41 }
42 return store, nil
43}
44
Solomon Hykes44faa072013-03-22 00:35:4945func (store *TagStore) Save() error {
Solomon Hykes680f40c2013-03-21 19:18:4746 // Store the json ball
47 jsonData, err := json.Marshal(store)
48 if err != nil {
49 return err
50 }
51 if err := ioutil.WriteFile(store.path, jsonData, 0600); err != nil {
52 return err
53 }
54 return nil
55}
56
Solomon Hykes44faa072013-03-22 00:35:4957func (store *TagStore) Reload() error {
Solomon Hykes680f40c2013-03-21 19:18:4758 jsonData, err := ioutil.ReadFile(store.path)
59 if err != nil {
60 return err
61 }
62 if err := json.Unmarshal(jsonData, store); err != nil {
63 return err
64 }
65 return nil
66}
67
Solomon Hykes640026e2013-03-22 23:07:1368func (store *TagStore) LookupImage(name string) (*Image, error) {
69 img, err := store.graph.Get(name)
70 if err != nil {
71 // FIXME: standardize on returning nil when the image doesn't exist, and err for everything else
72 // (so we can pass all errors here)
73 repoAndTag := strings.SplitN(name, ":", 2)
74 if len(repoAndTag) == 1 {
75 repoAndTag = append(repoAndTag, DEFAULT_TAG)
76 }
77 if i, err := store.GetImage(repoAndTag[0], repoAndTag[1]); err != nil {
78 return nil, err
79 } else if i == nil {
Guillaume J. Charmes004a5312013-03-26 12:28:1780 return nil, fmt.Errorf("Image does not exist: %s", name)
Solomon Hykes640026e2013-03-22 23:07:1381 } else {
82 img = i
83 }
Solomon Hykes49a78922013-03-22 03:06:2084 }
Solomon Hykes640026e2013-03-22 23:07:1385 return img, nil
86}
87
Solomon Hykes12049f92013-03-23 02:22:0688// Return a reverse-lookup table of all the names which refer to each image
89// Eg. {"43b5f19b10584": {"base:latest", "base:v1"}}
90func (store *TagStore) ById() map[string][]string {
91 byId := make(map[string][]string)
92 for repoName, repository := range store.Repositories {
93 for tag, id := range repository {
94 name := repoName + ":" + tag
95 if _, exists := byId[id]; !exists {
96 byId[id] = []string{name}
97 } else {
98 byId[id] = append(byId[id], name)
Solomon Hykes846a9e82013-03-26 22:30:1699 sort.Strings(byId[id])
Solomon Hykes12049f92013-03-23 02:22:06100 }
101 }
102 }
103 return byId
104}
105
106func (store *TagStore) ImageName(id string) string {
107 if names, exists := store.ById()[id]; exists && len(names) > 0 {
108 return names[0]
109 }
Guillaume J. Charmes2e69e172013-05-14 22:37:35110 return utils.TruncateId(id)
Solomon Hykes12049f92013-03-23 02:22:06111}
112
Solomon Hykesbf7602b2013-03-23 01:27:18113func (store *TagStore) Set(repoName, tag, imageName string, force bool) error {
114 img, err := store.LookupImage(imageName)
115 if err != nil {
116 return err
117 }
Solomon Hykes640026e2013-03-22 23:07:13118 if tag == "" {
119 tag = DEFAULT_TAG
120 }
121 if err := validateRepoName(repoName); err != nil {
122 return err
123 }
124 if err := validateTagName(tag); err != nil {
125 return err
Solomon Hykes49a78922013-03-22 03:06:20126 }
Solomon Hykes680f40c2013-03-21 19:18:47127 if err := store.Reload(); err != nil {
128 return err
129 }
Solomon Hykes44faa072013-03-22 00:35:49130 var repo Repository
Solomon Hykes680f40c2013-03-21 19:18:47131 if r, exists := store.Repositories[repoName]; exists {
132 repo = r
133 } else {
Solomon Hykes44faa072013-03-22 00:35:49134 repo = make(map[string]string)
Solomon Hykesbf7602b2013-03-23 01:27:18135 if old, exists := store.Repositories[repoName]; exists && !force {
136 return fmt.Errorf("Tag %s:%s is already set to %s", repoName, tag, old)
137 }
Solomon Hykes680f40c2013-03-21 19:18:47138 store.Repositories[repoName] = repo
139 }
Solomon Hykesbf7602b2013-03-23 01:27:18140 repo[tag] = img.Id
Solomon Hykes680f40c2013-03-21 19:18:47141 return store.Save()
142}
143
Solomon Hykes44faa072013-03-22 00:35:49144func (store *TagStore) Get(repoName string) (Repository, error) {
Solomon Hykes680f40c2013-03-21 19:18:47145 if err := store.Reload(); err != nil {
146 return nil, err
147 }
148 if r, exists := store.Repositories[repoName]; exists {
149 return r, nil
150 }
151 return nil, nil
152}
153
Solomon Hykes44faa072013-03-22 00:35:49154func (store *TagStore) GetImage(repoName, tag string) (*Image, error) {
Solomon Hykes680f40c2013-03-21 19:18:47155 repo, err := store.Get(repoName)
156 if err != nil {
157 return nil, err
158 } else if repo == nil {
159 return nil, nil
160 }
Solomon Hykes44faa072013-03-22 00:35:49161 if revision, exists := repo[tag]; exists {
Solomon Hykes680f40c2013-03-21 19:18:47162 return store.graph.Get(revision)
163 }
164 return nil, nil
165}
Solomon Hykes640026e2013-03-22 23:07:13166
167// Validate the name of a repository
168func validateRepoName(name string) error {
169 if name == "" {
170 return fmt.Errorf("Repository name can't be empty")
171 }
172 if strings.Contains(name, ":") {
173 return fmt.Errorf("Illegal repository name: %s", name)
174 }
175 return nil
176}
177
178// Validate the name of a tag
179func validateTagName(name string) error {
180 if name == "" {
181 return fmt.Errorf("Tag name can't be empty")
182 }
183 if strings.Contains(name, "/") || strings.Contains(name, ":") {
184 return fmt.Errorf("Illegal tag name: %s", name)
185 }
186 return nil
187}