// Test gets results of the earlier Next() call, & returns if we should continue! func (obj *PkgResAutoEdges) Test(input []bool) bool { if !obj.testIsNext { log.Fatal("Expecting a call to Next()") } // ack the svcUID's... if x := obj.svcUIDs; len(x) > 0 { if y := len(x); y != len(input) { log.Fatalf("Expecting %d value(s)!", y) } obj.svcUIDs = []ResUID{} // empty obj.testIsNext = false return true } count := len(obj.fileList) if count != len(input) { log.Fatalf("Expecting %d value(s)!", count) } obj.testIsNext = false // set after all the errors paths are past // while i do believe this algorithm generates the *correct* result, i // don't know if it does so in the optimal way. improvements welcome! // the basic logic is: // 0) Next() returns whatever is in fileList // 1) Test() computes the dirname of each file, and removes duplicates // and dirname's that have been in the path of an ack from input results // 2) It then simplifies the list by removing the common path prefixes // 3) Lastly, the remaining set of files (dirs) is used as new fileList // 4) We then iterate in (0) until the fileList is empty! var dirs = make([]string, count) done := []string{} for i := 0; i < count; i++ { dir := util.Dirname(obj.fileList[i]) // dirname of /foo/ should be / dirs[i] = dir if input[i] { done = append(done, dir) } } nodupes := util.StrRemoveDuplicatesInList(dirs) // remove duplicates nodones := util.StrFilterElementsInList(done, nodupes) // filter out done noempty := util.StrFilterElementsInList([]string{""}, nodones) // remove the "" from / obj.fileList = util.RemoveCommonFilePrefixes(noempty) // magic if len(obj.fileList) == 0 { // nothing more, don't continue return false } return true // continue, there are more files! }
// CheckApply checks the resource state and applies the resource if the bool // input is true. It returns error info and if the state check passed or not. func (obj *PkgRes) CheckApply(apply bool) (checkOK bool, err error) { log.Printf("%s: Check", obj.fmtNames(obj.getNames())) bus := packagekit.NewBus() if bus == nil { return false, fmt.Errorf("Can't connect to PackageKit bus.") } defer bus.Close() result, err := obj.pkgMappingHelper(bus) if err != nil { return false, errwrap.Wrapf(err, "The pkgMappingHelper failed") } packageMap := obj.groupMappingHelper() // map[string]string packageList := []string{obj.Name} packageList = append(packageList, util.StrMapKeys(packageMap)...) //stateList := []string{obj.State} //stateList = append(stateList, util.StrMapValues(packageMap)...) // TODO: at the moment, all the states are the same, but // eventually we might be able to drop this constraint! states, err := packagekit.FilterState(result, packageList, obj.State) if err != nil { return false, errwrap.Wrapf(err, "The FilterState method failed") } data, _ := result[obj.Name] // if above didn't error, we won't either! validState := util.BoolMapTrue(util.BoolMapValues(states)) // obj.State == "installed" || "uninstalled" || "newest" || "4.2-1.fc23" switch obj.State { case "installed": fallthrough case "uninstalled": fallthrough case "newest": if validState { return true, nil // state is correct, exit! } default: // version string if obj.State == data.Version && data.Version != "" { return true, nil } } // state is not okay, no work done, exit, but without error if !apply { return false, nil } // apply portion log.Printf("%s: Apply", obj.fmtNames(obj.getNames())) readyPackages, err := packagekit.FilterPackageState(result, packageList, obj.State) if err != nil { return false, err // fail } // these are the packages that actually need their states applied! applyPackages := util.StrFilterElementsInList(readyPackages, packageList) packageIDs, _ := packagekit.FilterPackageIDs(result, applyPackages) // would be same err as above var transactionFlags uint64 // initializes at the "zero" value of 0 if !obj.AllowUntrusted { // allow transactionFlags += packagekit.PK_TRANSACTION_FLAG_ENUM_ONLY_TRUSTED } // apply correct state! log.Printf("%s: Set: %v...", obj.fmtNames(util.StrListIntersection(applyPackages, obj.getNames())), obj.State) switch obj.State { case "uninstalled": // run remove // NOTE: packageID is different than when installed, because now // it has the "installed" flag added to the data portion if it!! err = bus.RemovePackages(packageIDs, transactionFlags) case "newest": // TODO: isn't this the same operation as install, below? err = bus.UpdatePackages(packageIDs, transactionFlags) case "installed": fallthrough // same method as for "set specific version", below default: // version string err = bus.InstallPackages(packageIDs, transactionFlags) } if err != nil { return false, err // fail } log.Printf("%s: Set: %v success!", obj.fmtNames(util.StrListIntersection(applyPackages, obj.getNames())), obj.State) return false, nil // success }