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  }