Beispiel #1
0
func (ctx *Context) modifyAdd(pkg *Package) error {
	var err error
	src := pkg.Dir
	if pkg.Status == StatusVendor {
		src, _, err = ctx.findImportDir("", pkg.Canonical)
		if err != nil {
			return err
		}
	}
	dest := filepath.Join(ctx.RootDir, ctx.VendorFolder, pathos.SlashToFilepath(pkg.Canonical))
	// TODO: This might cause other issues or might be hiding the underlying issues. Examine in depth later.
	if pathos.FileStringEquals(src, dest) {
		return nil
	}
	ctx.Operation = append(ctx.Operation, &Operation{
		Pkg:  pkg,
		Src:  src,
		Dest: dest,
	})

	// Update vendor file with correct Local field.
	vp := ctx.VendorFilePackageCanonical(pkg.Canonical)
	if vp == nil {
		vp = &vendorfile.Package{
			Add:       true,
			Canonical: pkg.Canonical,
			Local:     path.Join(ctx.VendorFileToFolder, pkg.Canonical),
		}
		ctx.VendorFile.Package = append(ctx.VendorFile.Package, vp)
	}

	// Find the VCS information.
	system, err := vcs.FindVcs(pkg.Gopath, src)
	if err != nil {
		return err
	}
	if system != nil {
		if system.Dirty {
			return ErrDirtyPackage{pkg.Canonical}
		}
		vp.Revision = system.Revision
		if system.RevisionTime != nil {
			vp.RevisionTime = system.RevisionTime.Format(time.RFC3339)
		}
	}

	mvSet := make(map[*Package]struct{}, 3)
	ctx.makeSet(pkg, mvSet)

	for r := range mvSet {
		to := path.Join(ctx.RootImportPath, ctx.VendorFolder, r.Canonical)
		dprintf("RULE: %s -> %s\n", r.Local, to)
		ctx.RewriteRule[r.Local] = to
	}

	return nil
}
Beispiel #2
0
func readVendorFile(vendorFilePath string) (*vendorfile.File, error) {
	vf := &vendorfile.File{}
	f, err := os.Open(vendorFilePath)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	err = vf.Unmarshal(f)
	if err != nil {
		return nil, err
	}
	// Determine if local field is relative to GOPATH or vendor file.
	// Change to relative to vendor file as needed.
	folder, _ := filepath.Split(vendorFilePath)
	relToFile := 0
	relToGOPATH := 0
	for _, pkg := range vf.Package {
		p := filepath.Join(folder, pathos.SlashToFilepath(pkg.Local))
		_, err := os.Stat(p)
		if os.IsNotExist(err) {
			relToGOPATH++
			continue
		}
		relToFile++
	}
	if relToFile > relToGOPATH || len(vf.Package) == 0 {
		return vf, nil
	}

	gopathList := strings.Split(os.Getenv("GOPATH"), string(os.PathListSeparator))
	gopath := ""
	for _, gp := range gopathList {
		if pathos.FileHasPrefix(folder, gp) {
			gopath = gp
			break
		}
	}
	if len(gopath) == 0 {
		return vf, nil
	}
	prefix := pathos.SlashToImportPath(pathos.FileTrimPrefix(folder, filepath.Join(gopath, "src")))
	prefix = strings.TrimPrefix(prefix, "/")
	for _, pkg := range vf.Package {
		pkg.Local = strings.TrimPrefix(pkg.Local, prefix)
	}

	return vf, nil
}
Beispiel #3
0
func (ctx *Context) modifyAdd(pkg *Package) error {
	var err error
	src := pkg.Dir
	if pkg.Status == StatusVendor {
		src, _, err = ctx.findImportDir("", pkg.Canonical)
		if err != nil {
			return err
		}
	}
	// If the canonical package is also the local package, then the package
	// isn't copied locally already and has already been checked for tags.
	// If it has been vendored the source still needs to be examined.
	// Examine here and add to the operations list.
	var ignoreFile []string
	if cpkg, found := ctx.Package[pkg.Canonical]; found {
		ignoreFile = cpkg.ignoreFile
	} else {
		srcDir, err := os.Open(src)
		if err != nil {
			return err
		}
		fl, err := srcDir.Readdir(-1)
		srcDir.Close()
		if err != nil {
			return err
		}
		for _, fi := range fl {
			if fi.IsDir() {
				continue
			}
			if fi.Name()[0] == '.' {
				continue
			}
			tags, err := ctx.getFileTags(filepath.Join(src, fi.Name()), nil)
			if err != nil {
				return err
			}

			for _, tag := range tags {
				for _, ignore := range ctx.ignoreTag {
					if tag == ignore {
						ignoreFile = append(ignoreFile, fi.Name())
					}
				}
			}
		}
	}
	dest := filepath.Join(ctx.RootDir, ctx.VendorFolder, pathos.SlashToFilepath(pkg.Canonical))
	// TODO: This might cause other issues or might be hiding the underlying issues. Examine in depth later.
	if pathos.FileStringEquals(src, dest) {
		return nil
	}
	ctx.Operation = append(ctx.Operation, &Operation{
		Pkg:        pkg,
		Src:        src,
		Dest:       dest,
		IgnoreFile: ignoreFile,
	})

	// Update vendor file with correct Local field.
	vp := ctx.VendorFilePackagePath(pkg.Canonical)
	if vp == nil {
		vp = &vendorfile.Package{
			Add:  true,
			Path: pkg.Canonical,
		}
		ctx.VendorFile.Package = append(ctx.VendorFile.Package, vp)
	}

	// Find the VCS information.
	system, err := vcs.FindVcs(pkg.Gopath, src)
	if err != nil {
		return err
	}
	if system != nil {
		if system.Dirty {
			return ErrDirtyPackage{pkg.Canonical}
		}
		vp.Revision = system.Revision
		if system.RevisionTime != nil {
			vp.RevisionTime = system.RevisionTime.Format(time.RFC3339)
		}
	}

	mvSet := make(map[*Package]struct{}, 3)
	ctx.makeSet(pkg, mvSet)

	for r := range mvSet {
		to := path.Join(ctx.RootImportPath, ctx.VendorFolder, r.Canonical)
		dprintf("RULE: %s -> %s\n", r.Local, to)
		ctx.RewriteRule[r.Canonical] = to
		ctx.RewriteRule[r.Local] = to
	}

	return nil
}
Beispiel #4
0
// AddImport adds the package to the context. The vendorFolder is where the
// package should be added to relative to the project root.
func (ctx *Context) ModifyImport(sourcePath string, mod Modify) error {
	var err error
	if !ctx.loaded || ctx.dirty {
		err = ctx.loadPackage()
		if err != nil {
			return err
		}
	}
	// Determine canonical and local import paths.
	sourcePath = pathos.SlashToImportPath(sourcePath)
	canonicalImportPath, err := ctx.findCanonicalPath(sourcePath)
	if err != nil {
		if mod != Remove {
			return err
		}
		if _, is := err.(ErrNotInGOPATH); !is {
			return err
		}
	}
	// If the import is already vendored, ensure we have the local path and not
	// the canonical path.
	localImportPath := sourcePath
	if vendPkg := ctx.VendorFilePackagePath(localImportPath); vendPkg != nil {
		localImportPath = path.Join(ctx.RootImportPath, ctx.RootToVendorFile, vendPkg.Path)
	}

	dprintf("AI: %s, L: %s, C: %s\n", sourcePath, localImportPath, canonicalImportPath)

	// Does the local import exist?
	//   If so either update or just return.
	//   If not find the disk path from the canonical path, copy locally and rewrite (if needed).
	pkg, foundPkg := ctx.Package[localImportPath]
	if !foundPkg {
		err = ctx.addSingleImport("", canonicalImportPath)
		if err != nil {
			return err
		}
		pkg, foundPkg = ctx.Package[canonicalImportPath]
		// Find by canonical path if stored by different local path.
		if !foundPkg {
			for _, p := range ctx.Package {
				if canonicalImportPath == p.Canonical {
					foundPkg = true
					pkg = p
					break
				}
			}
		}
		if !foundPkg {
			panic(fmt.Sprintf("Package %q should be listed internally but is not.", canonicalImportPath))
		}
	}

	localExists, err := hasGoFileInFolder(filepath.Join(ctx.RootDir, ctx.VendorFolder, pathos.SlashToFilepath(canonicalImportPath)))
	if err != nil {
		return err
	}
	if mod == Add && localExists {
		return ErrPackageExists{path.Join(ctx.RootImportPath, ctx.VendorFolder, canonicalImportPath)}
	}
	switch mod {
	case Add:
		return ctx.modifyAdd(pkg)
	case AddUpdate:
		return ctx.modifyAdd(pkg)
	case Update:
		return ctx.modifyAdd(pkg)
	case Remove:
		return ctx.modifyRemove(pkg)
	default:
		panic("mod switch: case not handled")
	}
}
Beispiel #5
0
func (ctx *Context) modifyAdd(pkg *Package) error {
	var err error
	src := pkg.OriginDir
	dprintf("found import: %q\n", src)
	// If the canonical package is also the local package, then the package
	// isn't copied locally already and has already been checked for tags.
	// If it has been vendored the source still needs to be examined.
	// Examine here and add to the operations list.
	var ignoreFile []string
	if cpkg, found := ctx.Package[pkg.Canonical]; found {
		ignoreFile = cpkg.ignoreFile
	} else {
		var err error
		ignoreFile, err = ctx.getIngoreFiles(src)
		if err != nil {
			return err
		}
	}
	dest := filepath.Join(ctx.RootDir, ctx.VendorFolder, pathos.SlashToFilepath(pkg.Canonical))
	// TODO: This might cause other issues or might be hiding the underlying issues. Examine in depth later.
	if pathos.FileStringEquals(src, dest) {
		return nil
	}
	dprintf("add op: %q\n", src)
	ctx.Operation = append(ctx.Operation, &Operation{
		Pkg:        pkg,
		Src:        src,
		Dest:       dest,
		IgnoreFile: ignoreFile,
	})

	// Update vendor file with correct Local field.
	vp := ctx.VendorFilePackagePath(pkg.Canonical)
	if vp == nil {
		vp = &vendorfile.Package{
			Add:  true,
			Path: pkg.Canonical,
		}
		ctx.VendorFile.Package = append(ctx.VendorFile.Package, vp)

		if pkg.Local != pkg.Canonical && pkg.inVendor {
			vp.Origin = pkg.Local
		}
	}
	vp.Tree = pkg.Tree

	// Find the VCS information.
	system, err := vcs.FindVcs(pkg.Gopath, src)
	if err != nil {
		return err
	}
	if system != nil {
		if system.Dirty {
			return ErrDirtyPackage{pkg.Canonical}
		}
		vp.Revision = system.Revision
		if system.RevisionTime != nil {
			vp.RevisionTime = system.RevisionTime.Format(time.RFC3339)
		}
	}

	mvSet := make(map[*Package]struct{}, 3)
	ctx.makeSet(pkg, mvSet)

	for r := range mvSet {
		to := path.Join(ctx.RootImportPath, ctx.VendorFolder, r.Canonical)
		dprintf("RULE: %s -> %s\n", r.Local, to)
		ctx.RewriteRule[r.Canonical] = to
		ctx.RewriteRule[r.Local] = to
	}

	return nil
}
Beispiel #6
0
// AddImport adds the package to the context. The vendorFolder is where the
// package should be added to relative to the project root.
func (ctx *Context) ModifyImport(sourcePath string, mod Modify) error {
	var err error
	if !ctx.loaded || ctx.dirty {
		err = ctx.loadPackage()
		if err != nil {
			return err
		}
	}
	tree := strings.HasSuffix(sourcePath, TreeSuffix)
	sourcePath = strings.TrimSuffix(sourcePath, TreeSuffix)

	// Determine canonical and local import paths.
	sourcePath = pathos.SlashToImportPath(sourcePath)
	canonicalImportPath, err := ctx.findCanonicalPath(sourcePath)
	if err != nil {
		if mod != Remove {
			return err
		}
		if _, is := err.(ErrNotInGOPATH); !is {
			return err
		}
	}
	// If the import is already vendored, ensure we have the local path and not
	// the canonical path.
	localImportPath := sourcePath
	if vendPkg := ctx.VendorFilePackagePath(localImportPath); vendPkg != nil {
		localImportPath = path.Join(ctx.RootImportPath, ctx.RootToVendorFile, vendPkg.Path)
	}

	dprintf("AI: %s, L: %s, C: %s\n", sourcePath, localImportPath, canonicalImportPath)

	// Does the local import exist?
	//   If so either update or just return.
	//   If not find the disk path from the canonical path, copy locally and rewrite (if needed).
	pkg, foundPkg := ctx.Package[localImportPath]
	if !foundPkg {
		err = ctx.addSingleImport("", canonicalImportPath)
		if err != nil {
			return err
		}
		pkg, foundPkg = ctx.Package[canonicalImportPath]
		// Find by canonical path if stored by different local path.
		if !foundPkg {
			for _, p := range ctx.Package {
				if canonicalImportPath == p.Canonical {
					foundPkg = true
					pkg = p
					break
				}
			}
		}
		if !foundPkg {
			panic(fmt.Sprintf("Package %q should be listed internally but is not.", canonicalImportPath))
		}
	}

	// Do not support setting "tree" on Remove.
	if tree && mod != Remove {
		pkg.Tree = true
	}

	// A restriction where packages cannot live inside a tree package.
	if mod != Remove {
		if pkg.Tree {
			children := ctx.findPackageChild(pkg)
			if len(children) > 0 {
				return ErrTreeChildren{path: pkg.Canonical, children: children}
			}
		}
		treeParents := ctx.findPackageParentTree(pkg)
		if len(treeParents) > 0 {
			return ErrTreeParents{path: pkg.Canonical, parents: treeParents}
		}
	}

	// TODO (DT): figure out how to upgrade a non-tree package to a tree package with correct checks.
	localExists, err := hasGoFileInFolder(filepath.Join(ctx.RootDir, ctx.VendorFolder, pathos.SlashToFilepath(canonicalImportPath)))
	if err != nil {
		return err
	}
	if mod == Add && localExists {
		return ErrPackageExists{path.Join(ctx.RootImportPath, ctx.VendorFolder, canonicalImportPath)}
	}
	dprintf("stage 2: begin!\n")
	switch mod {
	case Add:
		return ctx.modifyAdd(pkg)
	case AddUpdate:
		return ctx.modifyAdd(pkg)
	case Update:
		return ctx.modifyAdd(pkg)
	case Remove:
		return ctx.modifyRemove(pkg)
	case Fetch:
		return ctx.modifyFetch(pkg)
	default:
		panic("mod switch: case not handled")
	}
}