github.com/whyrusleeping/gx@v0.14.3/gxutil/publish.go (about) 1 package gxutil 2 3 import ( 4 "fmt" 5 "os" 6 "path/filepath" 7 "strings" 8 9 homedir "github.com/mitchellh/go-homedir" 10 gi "github.com/sabhiram/go-gitignore" 11 ) 12 13 func (pm *PM) PublishPackage(dir string, pkg *PackageBase) (string, error) { 14 // make sure we have the actual package dir, and not a hashdir 15 if _, err := os.Stat(filepath.Join(dir, PkgFileName)); err != nil { 16 // try appending the package name 17 _, err = os.Stat(filepath.Join(dir, pkg.Name, PkgFileName)) 18 if err != nil { 19 return "", fmt.Errorf("%s did not contain a package!", dir) 20 } 21 dir = filepath.Join(dir, pkg.Name) 22 } 23 24 gitig, err := gi.CompileIgnoreFile(filepath.Join(dir, ".gitignore")) 25 if err != nil && !os.IsNotExist(err) { 26 return "", err 27 } 28 29 home, err := homedir.Dir() 30 if err != nil { 31 return "", err 32 } 33 34 pgig := filepath.Join(home, ".gitignore") 35 var ggitig *gi.GitIgnore 36 37 if _, err := os.Stat(pgig); err == nil { 38 var err error 39 ggitig, err = gi.CompileIgnoreFile(pgig) 40 if err != nil { 41 return "", err 42 } 43 } 44 45 gxig, err := gi.CompileIgnoreFile(filepath.Join(dir, ".gxignore")) 46 if err != nil && !os.IsNotExist(err) { 47 return "", err 48 } 49 50 var files []string 51 filepath.Walk(dir, func(p string, info os.FileInfo, err error) error { 52 53 // ignore directories 54 if info.IsDir() { 55 return nil 56 } 57 58 // get relative path 59 rel := p[len(dir):] 60 if dir[len(dir)-1] != '/' { 61 rel = rel[1:] 62 } 63 64 // make relative path cross platform safe 65 rel = filepath.ToSlash(rel) 66 67 // respect gitignore 68 if gitig != nil && gitig.MatchesPath(rel) { 69 return nil 70 } 71 72 // respect global gitignore 73 if ggitig != nil && ggitig.MatchesPath(rel) { 74 return nil 75 } 76 77 // respect gxignore 78 if gxig != nil && gxig.MatchesPath(rel) { 79 return nil 80 } 81 82 // dont publish the git repo 83 if strings.HasPrefix(rel, ".git") { 84 return nil 85 } 86 87 // dont publish gx repo files 88 if strings.HasPrefix(rel, ".gx/") || strings.HasSuffix(rel, ".gxrc") { 89 return nil 90 } 91 92 files = append(files, rel) 93 return nil 94 }) 95 96 // we cant guarantee that the 'empty dir' object exists already 97 blank, err := pm.Shell().NewObject("unixfs-dir") 98 if err != nil { 99 return "", err 100 } 101 102 pm.blankDir = blank 103 104 pkgdir, err := pm.addFiles(dir, files) 105 if err != nil { 106 return "", err 107 } 108 109 final, err := pm.Shell().PatchLink(pm.blankDir, pkg.Name, pkgdir, true) 110 if err != nil { 111 return "", err 112 } 113 114 return final, pm.Shell().Pin(final) 115 } 116 117 type filetree struct { 118 children map[string]*filetree 119 } 120 121 func newFiletree() *filetree { 122 return &filetree{make(map[string]*filetree)} 123 } 124 125 func newFiletreeFromFiles(files []string) (*filetree, error) { 126 root := &filetree{make(map[string]*filetree)} 127 for _, f := range files { 128 f = strings.TrimRight(f, "/") 129 parts := strings.Split(f, "/") 130 if err := root.insert(parts); err != nil { 131 return nil, err 132 } 133 } 134 return root, nil 135 } 136 137 func (ft *filetree) insert(path []string) error { 138 if len(path) > 1 { 139 child, ok := ft.children[path[0]] 140 if !ok { 141 child = newFiletree() 142 ft.children[path[0]] = child 143 } 144 145 return child.insert(path[1:]) 146 } 147 148 if len(path) == 1 { 149 _, ok := ft.children[path[0]] 150 if ok { 151 return fmt.Errorf("path already exists: %s", path[0]) 152 } 153 154 ft.children[path[0]] = newFiletree() 155 return nil 156 } 157 158 panic("branch never reached") 159 } 160 161 func (pm *PM) addFiles(root string, files []string) (string, error) { 162 tree, err := newFiletreeFromFiles(files) 163 if err != nil { 164 return "", err 165 } 166 167 return pm.addTree(tree, root) 168 } 169 170 func (pm *PM) addFile(p string) (string, error) { 171 fi, err := os.Open(p) 172 if err != nil { 173 fmt.Printf("open failed: %s\n", err) 174 return "", err 175 } 176 defer fi.Close() 177 178 return pm.Shell().AddNoPin(fi) 179 } 180 181 func (pm *PM) addPathElem(v *filetree, f, cwd string) (string, error) { 182 if v == nil || len(v.children) == 0 { 183 184 // file or symlink here 185 p := filepath.Join(cwd, f) 186 stat, err := os.Lstat(p) 187 if err != nil { 188 fmt.Printf("file stat failed: %s\n", err) 189 return "", err 190 } 191 192 if stat.Mode()&os.ModeSymlink != 0 { 193 target, err := os.Readlink(p) 194 if err != nil { 195 return "", err 196 } 197 198 return pm.Shell().AddLink(target) 199 } 200 201 return pm.addFile(p) 202 } 203 204 return pm.addTree(v, filepath.Join(cwd, f)) 205 } 206 207 func (pm *PM) addTree(nd *filetree, cwd string) (string, error) { 208 cur := pm.blankDir 209 for f, v := range nd.children { 210 hash, err := pm.addPathElem(v, f, cwd) 211 if err != nil { 212 return "", err 213 } 214 patched, err := pm.Shell().Patch(cur, "add-link", f, hash) 215 if err != nil { 216 return "", err 217 } 218 219 cur = patched 220 } 221 222 return cur, nil 223 }