예제 #1
0
파일: remote.go 프로젝트: JoeHorn/drive
func (r *Remote) UpsertByComparison(args *upsertOpt) (f *File, err error) {
	/*
	   // TODO: (@odeke-em) decide:
	   //   + if to reject FIFO
	   //   + perform an assertion for fileStated.IsDir() == args.src.IsDir
	*/
	if args.src == nil {
		err = fmt.Errorf("bug on: src cannot be nil")
		return
	}

	var body io.Reader
	if !args.src.IsDir {
		body, err = os.Open(args.fsAbsPath)
		if err != nil {
			return
		}
	}

	bd := statos.NewReader(body)

	go func() {
		commChan := bd.ProgressChan()
		for n := range commChan {
			r.progressChan <- n
		}
	}()

	resultLoad := make(chan *tuple)

	go func() {
		emitter := func() (interface{}, error) {
			f, mediaInserted, err := r.upsertByComparison(bd, args)
			return &tuple{first: f, second: mediaInserted, last: err}, err
		}

		retrier := retryableChangeOp(emitter, args.debug)

		res, err := expb.ExponentialBackOffSync(retrier)
		resultLoad <- &tuple{first: res, last: err}
	}()

	result := <-resultLoad
	if result == nil {
		return f, err
	}

	tup, tupOk := result.first.(*tuple)
	if tupOk {
		ff, fOk := tup.first.(*File)
		if fOk {
			f = ff
		}

		mediaInserted, mediaOk := tup.second.(bool)

		// Case in which for example just Chtime-ing
		if mediaOk && !mediaInserted && f != nil {
			chunks := chunkInt64(f.Size)
			for n := range chunks {
				r.progressChan <- n
			}
		}

		errV, errCastOk := tup.last.(error)
		if errCastOk {
			err = errV
		}
	}

	return f, err
}
예제 #2
0
파일: remote.go 프로젝트: nawawi/drive
func (r *Remote) UpsertByComparison(args *upsertOpt) (f *File, err error) {
	/*
	   // TODO: (@odeke-em) decide:
	   //   + if to reject FIFO
	   //   + perform an assertion for fileStated.IsDir() == args.src.IsDir
	*/
	if args.src == nil {
		err = illogicalStateErr(fmt.Errorf("bug on: src cannot be nil"))
		return
	}

	var body io.Reader
	var cleanUp func() error

	if !args.src.IsDir {
		// In relation to issue #612, since we are not only resolving
		// relative to the current working directory, we should try reading
		// first from the source's original local fsAbsPath aka `BlobAt`
		// because the resolved path might be different from the original path.
		fsAbsPath := args.src.BlobAt
		if fsAbsPath == "" {
			fsAbsPath = args.fsAbsPath
		}

		if args.shouldUploadBody() {
			file, err := os.Open(fsAbsPath)
			if err != nil {
				return nil, err
			}

			// We need to make sure that we close all open handles.
			// See Issue https://github.com/odeke-em/drive/issues/711.
			cleanUp = file.Close
			body = file
		}
	}

	bd := statos.NewReader(body)

	go func() {
		commChan := bd.ProgressChan()
		for n := range commChan {
			r.progressChan <- n
		}
	}()

	resultLoad := make(chan *tuple)

	go func() {
		if cleanUp != nil {
			defer cleanUp()
		}

		emitter := func() (interface{}, error) {
			f, mediaInserted, err := r.upsertByComparison(bd, args)
			return &tuple{first: f, second: mediaInserted, last: err}, err
		}

		retrier := retryableChangeOp(emitter, args.debug, args.retryCount)

		res, err := expb.ExponentialBackOffSync(retrier)
		resultLoad <- &tuple{first: res, last: err}
	}()

	result := <-resultLoad
	if result == nil {
		return f, err
	}

	tup, tupOk := result.first.(*tuple)
	if tupOk {
		ff, fOk := tup.first.(*File)
		if fOk {
			f = ff
		}

		mediaInserted, mediaOk := tup.second.(bool)

		// Case in which for example just Chtime-ing
		if mediaOk && !mediaInserted && f != nil {
			chunks := chunkInt64(f.Size)
			for n := range chunks {
				r.progressChan <- n
			}
		}

		errV, errCastOk := tup.last.(error)
		if errCastOk {
			err = errV
		}
	}

	return f, err
}