func bundlerNew(bm *BundleManager) *bundler {
	self := &bundler{bm: bm, wake: sync.NewCond(&sync.Mutex{})}
	err := bm.BundleStateChangeWatchSet(BundleState_ToBundle, func(user string, bundle_id int, state BundleState) { self.Wakeup() })
	if err != nil {
		log.Printf("Failed to register wakeup callback with the bundle manager.")
		return nil
	}
	go func() {
		for {
			found := false
			ids, err := self.bm.bundleIdsForStateGet(BundleState_ToBundle)
			if err == nil && ids != nil {
				for user, list := range ids {
					for _, id := range list {
						log.Printf("Got bundles %v %v\n", user, id)
						bundle_filename := filepath.Join(common.BaseDir, "bundles", "inprogress", strconv.Itoa(id)+".tar")
						file, err := os.Create(bundle_filename)
						if err != nil {
							log.Printf("Could not open temp file. %v", err)
							continue
						}
						file.Close()
						if common.System {
							if platform.PlatformGet() == platform.Linux {
								cmd := exec.Command("setfacl", "-m", "user:"+user+":rw", bundle_filename)
								err = cmd.Run()
								if err != nil {
									log.Printf("Failed to set acl on bundle. %v\n", err)
									continue
								}
							} else if platform.PlatformGet() == platform.Windows {
								//TODO - remove or fix so that permissions are set for system user only.
								/*userstr := common.UserdDefaultUsername() + ":C"
								err = common.Cacls(bundle_filename, "/p", "NT AUTHORITY\\SYSTEM:f", userstr, "BUILTIN\\Administrators:F")
								if err != nil {
									log.Printf("Failed to run cacls %v\n", err)
									continue
								}*/
							}
						}
						err = bundleFiles(bundle_filename, user, id)
						if err != nil {
							continue
						}
						var newstate BundleState
						metadata_filename := filepath.Join(common.BaseDir, "bundles", "inprogress", strconv.Itoa(id)+".txt")
						file, err = os.Create(metadata_filename)
						if err != nil {
							log.Printf("Could not open temp file. %v", err)
							continue
						} else {
							err = writeMetadata(self.bm, user, id, file)
							file.Close()
							if err != nil {
								continue
							}
							_, _, fe, _, err := common.UserBundleFile(user, bundle_filename, metadata_filename, "metadata.txt")
							if err != nil || rpc.BundleFileErrorIsError(fe) {
								log.Printf("Failed to add metadata to bundle. %v", err)
								continue
							}
							newstate = BundleState_ToUpload
						}
						if common.System {
							if platform.PlatformGet() == platform.Linux {
								cmd := exec.Command("setfacl", "-x", "user:"+user, bundle_filename)
								err = cmd.Run()
								if err != nil {
									log.Printf("Failed to remove acl on bundle. %v\n", err)
									continue
								}
							} else if platform.PlatformGet() == platform.Windows {
								err = common.Cacls(bundle_filename, "/p", "NT AUTHORITY\\SYSTEM:f", "BUILTIN\\Administrators:F")
								if err != nil {
									log.Printf("Failed to run cacls %v\n", err)
									continue
								}
							}
						}
						bundle_new_filename := filepath.Join(common.BaseDir, "bundles", strconv.Itoa(id)+".tar")
						os.Remove(bundle_new_filename)
						err = os.Rename(bundle_filename, bundle_new_filename)
						if err != nil {
							log.Printf("Failed to rename bundle. %v\n", err)
							continue
						}
						err = bm.bundleStringSet(user, id, "bundle_location", bundle_new_filename)
						if err != nil {
							log.Printf("Failed to set bundle location. %v\n", err)
							continue
						}
						err = bm.BundleStateSet(user, id, newstate)
						if err != nil {
							log.Printf("Failed to transition bundle from bundling to upload. %v\n", err)
							continue
						}
						found = true
					}
				}
			}
			if found == false {
				self.wake.L.Lock()
				count, err := self.bm.bundleIdsForStateCount(BundleState_ToBundle)
				if err == nil && count < 1 {
					self.wake.Wait()
				}
				self.wake.L.Unlock()
			}
		}
	}()
	return self
}
func bundleFiles(bundle_filename string, user string, bundle_id int) error {
	b, err := bm.BundleGet(user, bundle_id)
	if err != nil {
		return err
	}
	bfs, err := b.FilesGet()
	if err != nil {
		log.Printf("Failed to get files from bundle.\n")
		return nil
	}
	for _, bf := range bfs {
		pacifica_filename, err := bf.PacificaFilenameGet()
		if err != nil {
			return err
		}
		if strings.HasPrefix(pacifica_filename, "/") {
			pacifica_filename = pacifica_filename[1:]
		}
		local_filename, err := bf.LocalFilenameGet()
		if err != nil {
			return err
		}
		disable_on_error, err := bf.DisableOnErrorGet()
		if err != nil {
			return err
		}
		log.Printf("To bundle: %v %v %v\n", bundle_filename, local_filename, pacifica_filename)
		result, sha1, fe, mtime, err := common.UserBundleFile(user, bundle_filename, local_filename, pacifica_filename)
		if err != nil {
			log.Printf("Failed to talk to the userd bundler. %v\n", err)
			return err
		}
		if rpc.BundleFileErrorIsError(fe) {
			if rpc.BundleFileErrorIsTransient(fe, !disable_on_error) {
				log.Printf("Transient issue. %v\n", fe)
				return errors.New("Transient error.")
			} else if disable_on_error && rpc.BundleFileErrorIsTransientError(fe) {
				//FIXME better error message.
				log.Printf("Transient error. %v\n", fe)
				err = bm.BundleFileStringSet(user, bf.bundle.id, bf.id, "disable_on_error_msg", strconv.Itoa(int(fe)))
				if err != nil {
					return err
				}
				continue
			} else if rpc.BundleFileErrorIsPermanentError(fe, !disable_on_error) {
				log.Printf("Permanent error. %v\n", fe)
				err = bm.BundleStateSet(user, bundle_id, BundleState_Error)
				if err != nil {
					log.Printf("Failed to transition bundle to error state. %v\n", err)
					return err
				}
				err = bm.bundleStringSet(user, bundle_id, "error", "Bundle Error")
				if err != nil {
					log.Printf("Failed to set error message. %v\n", err)
					return err
				}
				//FIXME better error message.
				err = bm.BundleFileStringSet(user, bf.bundle.id, bf.id, "disable_on_error_msg", strconv.Itoa(int(fe)))
				if err != nil {
					return err
				}
				return errors.New("PermanentError")
			}
		}
		err = bf.Sha1Set(sha1)
		if err != nil {
			log.Printf("Failed to set sha1. %v\n", err)
			return errors.New("Sha1")
		}
		err = bf.MtimeSet(mtime)
		if err != nil {
			log.Printf("Failed to set  mtime. %v\n", err)
			return errors.New("Mtime")
		}
		log.Printf("Got from bundler: %v %v %v\n", fe, result, sha1)
	}
	return nil
}