func scmStatusSelectively(sandboxPath string, scanRoots *[]string, m mode) (*status, error) {
	// Load up existing metadata and prepare fresh metadata
	oldMetaData := newMetaData()
	// If the load fails, it's not a problem, just empty
	err := oldMetaData.load(filepath.Join(sandboxPath, metadataFileName))

	if err != nil {
		return nil, simpleWarning("Not a sandbox")
	}

	status := newStatus(sandboxPath, m)
	status.metaData = oldMetaData

	// Delete any existing staging area
	if m == STAGE {
		err = os.RemoveAll(status.copyPath)
		if err != nil {
			panic(err)
		}
	}

	if scanRoots == nil {
		scanRoots = &[]string{sandboxPath}
	}

	// Walk the current directory structure looking for changed items
	for _, scanPath := range *scanRoots {
		err = filepath.Walk(scanPath, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				// One of the errors we can receive here is that the file no longer
				// exists, which is perfectly reasonable. Continue processing anyway.
				return nil
			}

			if path == sandboxPath {
				return nil
			}

			ignored, err := IsIgnored(path)
			if err != nil {
				return err
			}

			if ignored && info.IsDir() {
				return filepath.SkipDir
			} else if ignored {
				return nil
			}

			meta, ok := oldMetaData.get(path, sandboxPath)

			// Metadata doesn't exist for this file, so it must be added
			if !ok {
				status.fileAdded(path, sandboxPath)
				return nil
			}

			if !info.IsDir() {
				// The modified time is not a good enough check to see if the
				//  file is modified or not.
				// Different sizes mean that the file has changed for sure
				if meta.Size != info.Size() {
					status.fileModified(meta, path, sandboxPath)
				} else {
					// Check the hashes
					file, err := os.Open(path)
					if err != nil {
						return err
					}
					defer file.Close()

					hash := sha1.New()
					_, err = io.Copy(hash, file)

					if err != nil {
						return err
					}

					newHash := base64.StdEncoding.EncodeToString(hash.Sum(nil))

					if meta.Hash != newHash {
						status.fileModified(meta, path, sandboxPath)
					}
				}
			}

			return nil
		})

		if err != nil {
			return nil, err
		}
	}

	// Walk the metadata to find any items that don't exist
	for path, meta := range oldMetaData.pathMap {
		fullpath := filepath.Join(sandboxPath, path)
		_, err := os.Stat(fullpath)
		if err != nil {
			status.fileDeleted(meta, fullpath, sandboxPath)
		}
	}

	return status, nil
}
// Search the local directory for changes. The scanRoots is an array of full paths
// (ie not relative) within the sandboxPath. scanRoots may be 'nil', in which case
// we search from the sandboxPath.
Search the local directory for changes. The scanRoots is an array of full paths
within the sandboxPath. scanRoots may be 'nil', in which case
we search from the sandboxPath.
// Search the local directory for changes . The scanRoots is an array of full paths // ( ie not relative ) within the sandboxPath . scanRoots may be ' nil ' in which case // we search from the sandboxPath .
func scmStatusSelectively(sandboxPath string, scanRoots *[]string, m mode) (*status, error) {
	oldMetaData := newMetaData()
	err := oldMetaData.load(filepath.Join(sandboxPath, metadataFileName))
	if err != nil {
		return nil, simpleWarning("Not a sandbox")
	}
	status := newStatus(sandboxPath, m)
	status.metaData = oldMetaData
	if m == STAGE {
		err = os.RemoveAll(status.copyPath)
		if err != nil {
			panic(err)
		}
	}
	if scanRoots == nil {
		scanRoots = &[]string{sandboxPath}
	}
	for _, scanPath := range *scanRoots {
		err = filepath.Walk(scanPath, func(path string, info os.FileInfo, err error) error {
			if err != nil {
				return nil
			}
			if path == sandboxPath {
				return nil
			}
			ignored, err := IsIgnored(path)
			if err != nil {
				return err
			}
			if ignored && info.IsDir() {
				return filepath.SkipDir
			} else if ignored {
				return nil
			}
			meta, ok := oldMetaData.get(path, sandboxPath)
			if !ok {
				status.fileAdded(path, sandboxPath)
				return nil
			}
			if !info.IsDir() {
				if meta.Size != info.Size() {
					status.fileModified(meta, path, sandboxPath)
				} else {
					file, err := os.Open(path)
					if err != nil {
						return err
					}
					defer file.Close()
					hash := sha1.New()
					_, err = io.Copy(hash, file)
					if err != nil {
						return err
					}
					newHash := base64.StdEncoding.EncodeToString(hash.Sum(nil))
					if meta.Hash != newHash {
						status.fileModified(meta, path, sandboxPath)
					}
				}
			}
			return nil
		})
		if err != nil {
			return nil, err
		}
	}
	for path, meta := range oldMetaData.pathMap {
		fullpath := filepath.Join(sandboxPath, path)
		_, err := os.Stat(fullpath)
		if err != nil {
			status.fileDeleted(meta, fullpath, sandboxPath)
		}
	}
	return status, nil
}
func scmStatusSelectively ( sandboxPath string , scanRoots * [ ] string , m mode ) ( * status , error ) { oldMetaData := newMetaData ( ) err := oldMetaData . load ( filepath . Join ( sandboxPath , metadataFileName ) ) if err != nil { return nil , simpleWarning ( " " ) } status := newStatus ( sandboxPath , m ) status . metaData = oldMetaData if m == STAGE { err = os . RemoveAll ( status . copyPath ) if err != nil { panic ( err ) } } if scanRoots == nil { scanRoots = & [ ] string { sandboxPath } } for _ , scanPath := range * scanRoots { err = filepath . Walk ( scanPath , func ( path string , info os . FileInfo , err error ) error { if err != nil { return nil } if path == sandboxPath { return nil } ignored , err := IsIgnored ( path ) if err != nil { return err } if ignored && info . IsDir ( ) { return filepath . SkipDir } else if ignored { return nil } meta , ok := oldMetaData . get ( path , sandboxPath ) if ! ok { status . fileAdded ( path , sandboxPath ) return nil } if ! info . IsDir ( ) { if meta . Size != info . Size ( ) { status . fileModified ( meta , path , sandboxPath ) } else { file , err := os . Open ( path ) if err != nil { return err } defer file . Close ( ) hash := sha1 . New ( ) _ , err = io . Copy ( hash , file ) if err != nil { return err } newHash := base64 . StdEncoding . EncodeToString ( hash . Sum ( nil ) ) if meta . Hash != newHash { status . fileModified ( meta , path , sandboxPath ) } } } return nil } ) if err != nil { return nil , err } } for path , meta := range oldMetaData . pathMap { fullpath := filepath . Join ( sandboxPath , path ) _ , err := os . Stat ( fullpath ) if err != nil { status . fileDeleted ( meta , fullpath , sandboxPath ) } } return status , nil }
Search the local directory for changes.
Search the local directory for changes .
// Load up existing metadata and prepare fresh metadata // If the load fails, it's not a problem, just empty // Delete any existing staging area // Walk the current directory structure looking for changed items // One of the errors we can receive here is that the file no longer // exists, which is perfectly reasonable. Continue processing anyway. // Metadata doesn't exist for this file, so it must be added // The modified time is not a good enough check to see if the //  file is modified or not. // Different sizes mean that the file has changed for sure // Check the hashes // Walk the metadata to find any items that don't exist