github.com/stackdocker/rkt@v0.10.1-0.20151109095037-1aa827478248/tools/quickrm/main.go (about) 1 // Copyright 2015 The rkt Authors 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 package main 16 17 import ( 18 "bufio" 19 "flag" 20 "fmt" 21 "os" 22 "path/filepath" 23 "sort" 24 "strconv" 25 26 "github.com/coreos/rkt/tools/common" 27 ) 28 29 // processor processes words from files generated by make 30 type processor interface { 31 kind() string 32 setWordsNumber(number int) 33 processWord(word string) error 34 getList() []string 35 } 36 37 // fileProcessor is the simplest from all processor 38 // implementations. Nothing special needs to be done for regular 39 // files, so it simply appends all the data passed to it. 40 type fileProcessor struct { 41 list []string 42 } 43 44 // symlinkProcessor prepares symlinks for removal - it makes sure that 45 // the directory part of a path to symlink has no symlinks in it. This 46 // is to make sure, that if a symlink is removed, then we can remove 47 // also other symlinks that were previously accessible via the just 48 // removed symlink. 49 type symlinkProcessor struct { 50 list []string 51 } 52 53 // dirProcessor, like symlinkProcessor, evaluates symlinks in paths it 54 // receives. It also sorts the directories, so the leaves are removed 55 // first. 56 type dirProcessor struct { 57 set map[string]struct{} 58 } 59 60 type items struct { 61 kind string 62 list []string 63 } 64 65 type kindData struct { 66 filename string 67 option string 68 proc processor 69 } 70 71 func main() { 72 allItems := getItems() 73 74 failed := false 75 for _, i := range allItems { 76 for _, el := range i.list { 77 if err := os.Remove(el); err != nil { 78 if os.IsNotExist(err) { 79 continue 80 } 81 common.Warn("Failed to remove %s %q: %v", i.kind, el, err) 82 failed = true 83 } 84 } 85 } 86 if failed { 87 os.Exit(1) 88 } 89 } 90 91 func getItems() []items { 92 kinds := []*kindData{ 93 &kindData{ 94 option: "files", 95 proc: &fileProcessor{}, 96 }, 97 &kindData{ 98 option: "symlinks", 99 proc: &symlinkProcessor{}, 100 }, 101 &kindData{ 102 option: "dirs", 103 proc: &dirProcessor{}, 104 }, 105 } 106 107 for _, k := range kinds { 108 flag.StringVar(&k.filename, k.option, "", fmt.Sprintf("List of %s", k.option)) 109 } 110 flag.Parse() 111 for _, k := range kinds { 112 if k.filename == "" { 113 common.Die("No --%s parameter passed", k.option) 114 } 115 } 116 117 allItems := make([]items, 0, len(kinds)) 118 for _, k := range kinds { 119 l, err := getList(k.filename, k.proc) 120 if err != nil { 121 common.Die("Failed to get %s list: %v", k.proc.kind(), err) 122 } 123 allItems = append(allItems, items{ 124 kind: k.proc.kind(), 125 list: l, 126 }) 127 } 128 129 return allItems 130 } 131 132 func getList(file string, proc processor) ([]string, error) { 133 fd, err := os.Open(file) 134 if err != nil { 135 return nil, fmt.Errorf("failed to open %s list %q: %v", proc.kind(), file, err) 136 } 137 defer fd.Close() 138 sc := bufio.NewScanner(fd) 139 sc.Split(bufio.ScanWords) 140 if !sc.Scan() { 141 if err := sc.Err(); err != nil { 142 return nil, fmt.Errorf("failed to read %s list %q: %v", proc.kind(), file, err) 143 } 144 return nil, fmt.Errorf("failed to parse %s list %q: premature end of file", proc.kind(), file) 145 } 146 num, err := strconv.Atoi(sc.Text()) 147 if err != nil { 148 return nil, fmt.Errorf("failed to parse first line of %s list %q: %v", proc.kind(), file, err) 149 } 150 proc.setWordsNumber(num) 151 for sc.Scan() { 152 if err := proc.processWord(sc.Text()); err != nil { 153 return nil, fmt.Errorf("failed to process %s from %s list %q: %v", sc.Text(), proc.kind(), file, err) 154 } 155 } 156 if err := sc.Err(); err != nil { 157 return nil, fmt.Errorf("failed to read %s list %q: %v", proc.kind(), file, err) 158 } 159 return proc.getList(), nil 160 } 161 162 // file processor 163 164 func (proc *fileProcessor) kind() string { 165 return "file" 166 } 167 168 func (proc *fileProcessor) setWordsNumber(number int) { 169 proc.list = make([]string, 0, number) 170 } 171 172 func (proc *fileProcessor) processWord(file string) error { 173 if file != "" { 174 proc.list = append(proc.list, file) 175 } 176 return nil 177 } 178 179 func (proc *fileProcessor) getList() []string { 180 return proc.list 181 } 182 183 // symlink processor 184 185 func (proc *symlinkProcessor) kind() string { 186 return "symlink" 187 } 188 189 func (proc *symlinkProcessor) setWordsNumber(number int) { 190 proc.list = make([]string, 0, number) 191 } 192 193 func (proc *symlinkProcessor) processWord(symlink string) error { 194 if symlink == "" { 195 return nil 196 } 197 symlinkDir := filepath.Dir(symlink) 198 symlinkBase := filepath.Base(symlink) 199 realSymlinkDir, err := filepath.EvalSymlinks(symlinkDir) 200 if err != nil { 201 if os.IsNotExist(err) { 202 return nil 203 } 204 return fmt.Errorf("failed to evaluate symlinks for symlink dir %q: %v", symlinkDir, err) 205 } 206 proc.list = append(proc.list, filepath.Join(realSymlinkDir, symlinkBase)) 207 return nil 208 } 209 210 func (proc *symlinkProcessor) getList() []string { 211 return proc.list 212 } 213 214 // dir processor 215 216 func (proc *dirProcessor) kind() string { 217 return "directory" 218 } 219 220 func (proc *dirProcessor) setWordsNumber(number int) { 221 proc.set = make(map[string]struct{}, number) 222 } 223 224 func (proc *dirProcessor) processWord(dir string) error { 225 if dir == "" { 226 return nil 227 } 228 realDir, err := filepath.EvalSymlinks(dir) 229 if err != nil { 230 if os.IsNotExist(err) { 231 return nil 232 } 233 return fmt.Errorf("failed to evaluate symlinks for dir %q: %v", dir, err) 234 } 235 proc.set[realDir] = struct{}{} 236 return nil 237 } 238 239 func (proc *dirProcessor) getList() []string { 240 list := make([]string, 0, len(proc.set)) 241 for d := range proc.set { 242 list = append(list, d) 243 } 244 sort.Sort(sort.Reverse(sort.StringSlice(list))) 245 return list 246 }