github.com/mfpierre/corectl@v0.5.6/list.go (about) 1 // Copyright 2015 - António Meireles <antonio.meireles@reformi.st> 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 // http://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 // 15 16 package main 17 18 import ( 19 "encoding/json" 20 "fmt" 21 "io/ioutil" 22 "os" 23 "path" 24 "path/filepath" 25 "time" 26 27 "github.com/blang/semver" 28 "github.com/spf13/cobra" 29 ) 30 31 var ( 32 lsCmd = &cobra.Command{ 33 Use: "ls", 34 Aliases: []string{"list"}, 35 Short: "Lists locally available CoreOS images", 36 PreRunE: defaultPreRunE, 37 RunE: lsCommand, 38 } 39 ) 40 41 func lsCommand(cmd *cobra.Command, args []string) (err error) { 42 var ( 43 channels []string 44 local map[string]semver.Versions 45 ) 46 if local, err = localImages(); err != nil { 47 return 48 } 49 50 if engine.rawArgs.GetBool("all") { 51 channels = DefaultChannels 52 } else { 53 channels = append(channels, 54 normalizeChannelName(engine.rawArgs.GetString("channel"))) 55 } 56 if engine.rawArgs.GetBool("json") { 57 var pp []byte 58 if len(channels) == 1 { 59 if pp, err = json.MarshalIndent( 60 local[normalizeChannelName(engine.rawArgs.GetString("channel"))], 61 "", " "); err != nil { 62 return 63 } 64 } else { 65 if pp, err = json.MarshalIndent(local, "", " "); err != nil { 66 return 67 } 68 } 69 fmt.Println(string(pp)) 70 return 71 } 72 fmt.Println("locally available images") 73 for _, i := range channels { 74 var header bool 75 for _, d := range local[i] { 76 if !header { 77 fmt.Printf(" - %s channel \n", i) 78 header = true 79 } 80 fmt.Println(" -", d.String()) 81 } 82 } 83 return 84 } 85 86 func init() { 87 lsCmd.Flags().String("channel", "alpha", "CoreOS channel") 88 lsCmd.Flags().BoolP("all", "a", false, "browses all channels") 89 lsCmd.Flags().BoolP("json", "j", false, 90 "outputs in JSON for easy 3rd party integration") 91 RootCmd.AddCommand(lsCmd) 92 } 93 94 func localImages() (local map[string]semver.Versions, err error) { 95 var ( 96 files []os.FileInfo 97 f os.FileInfo 98 channel string 99 stamp, _ = time.Parse("2006-01-02T15:04:05MST", LatestImageBreackage) 100 ) 101 local = make(map[string]semver.Versions, 0) 102 for _, channel = range DefaultChannels { 103 if files, err = ioutil.ReadDir(filepath.Join(engine.imageDir, 104 channel)); err != nil { 105 return 106 } 107 var v semver.Versions 108 for _, f = range files { 109 if f.IsDir() { 110 ok := true 111 var ff string 112 for _, ff = range []string{"coreos_production_pxe.vmlinuz", 113 "coreos_production_pxe_image.cpio.gz"} { 114 if _, err = os.Stat(path.Join(engine.imageDir, 115 channel, f.Name(), ff)); err != nil { 116 ok = false 117 break 118 } 119 } 120 if ok && f.ModTime().After(stamp) { 121 var s semver.Version 122 if s, err = semver.Make(f.Name()); err != nil { 123 return 124 } 125 v = append(v, s) 126 } else { 127 // force rebuild if local image assembled before last time 128 // we changed its expcted format or something got missing 129 if err = os.RemoveAll(path.Join(engine.imageDir, channel, 130 f.Name(), ff)); err != nil { 131 return 132 } 133 } 134 } 135 } 136 semver.Sort(v) 137 local[channel] = v 138 } 139 return 140 }