github.com/pensu/helm@v2.6.1+incompatible/pkg/repo/repo.go (about)

     1  /*
     2  Copyright 2016 The Kubernetes Authors All rights reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package repo // import "k8s.io/helm/pkg/repo"
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"time"
    25  
    26  	"github.com/facebookgo/atomicfile"
    27  	"github.com/ghodss/yaml"
    28  )
    29  
    30  // ErrRepoOutOfDate indicates that the repository file is out of date, but
    31  // is fixable.
    32  var ErrRepoOutOfDate = errors.New("repository file is out of date")
    33  
    34  // RepoFile represents the repositories.yaml file in $HELM_HOME
    35  type RepoFile struct {
    36  	APIVersion   string    `json:"apiVersion"`
    37  	Generated    time.Time `json:"generated"`
    38  	Repositories []*Entry  `json:"repositories"`
    39  }
    40  
    41  // NewRepoFile generates an empty repositories file.
    42  //
    43  // Generated and APIVersion are automatically set.
    44  func NewRepoFile() *RepoFile {
    45  	return &RepoFile{
    46  		APIVersion:   APIVersionV1,
    47  		Generated:    time.Now(),
    48  		Repositories: []*Entry{},
    49  	}
    50  }
    51  
    52  // LoadRepositoriesFile takes a file at the given path and returns a RepoFile object
    53  //
    54  // If this returns ErrRepoOutOfDate, it also returns a recovered RepoFile that
    55  // can be saved as a replacement to the out of date file.
    56  func LoadRepositoriesFile(path string) (*RepoFile, error) {
    57  	b, err := ioutil.ReadFile(path)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	r := &RepoFile{}
    63  	err = yaml.Unmarshal(b, r)
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  
    68  	// File is either corrupt, or is from before v2.0.0-Alpha.5
    69  	if r.APIVersion == "" {
    70  		m := map[string]string{}
    71  		if err = yaml.Unmarshal(b, &m); err != nil {
    72  			return nil, err
    73  		}
    74  		r := NewRepoFile()
    75  		for k, v := range m {
    76  			r.Add(&Entry{
    77  				Name:  k,
    78  				URL:   v,
    79  				Cache: fmt.Sprintf("%s-index.yaml", k),
    80  			})
    81  		}
    82  		return r, ErrRepoOutOfDate
    83  	}
    84  
    85  	return r, nil
    86  }
    87  
    88  // Add adds one or more repo entries to a repo file.
    89  func (r *RepoFile) Add(re ...*Entry) {
    90  	r.Repositories = append(r.Repositories, re...)
    91  }
    92  
    93  // Update attempts to replace one or more repo entries in a repo file. If an
    94  // entry with the same name doesn't exist in the repo file it will add it.
    95  func (r *RepoFile) Update(re ...*Entry) {
    96  	for _, target := range re {
    97  		found := false
    98  		for j, repo := range r.Repositories {
    99  			if repo.Name == target.Name {
   100  				r.Repositories[j] = target
   101  				found = true
   102  				break
   103  			}
   104  		}
   105  		if !found {
   106  			r.Add(target)
   107  		}
   108  	}
   109  }
   110  
   111  // Has returns true if the given name is already a repository name.
   112  func (r *RepoFile) Has(name string) bool {
   113  	for _, rf := range r.Repositories {
   114  		if rf.Name == name {
   115  			return true
   116  		}
   117  	}
   118  	return false
   119  }
   120  
   121  // Remove removes the entry from the list of repositories.
   122  func (r *RepoFile) Remove(name string) bool {
   123  	cp := []*Entry{}
   124  	found := false
   125  	for _, rf := range r.Repositories {
   126  		if rf.Name == name {
   127  			found = true
   128  			continue
   129  		}
   130  		cp = append(cp, rf)
   131  	}
   132  	r.Repositories = cp
   133  	return found
   134  }
   135  
   136  // WriteFile writes a repositories file to the given path.
   137  func (r *RepoFile) WriteFile(path string, perm os.FileMode) error {
   138  	f, err := atomicfile.New(path, perm)
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	data, err := yaml.Marshal(r)
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	_, err = f.File.Write(data)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	return f.Close()
   154  }