19164: add a few flags to the compute image builder script.
[arvados.git] / tools / sync-groups / sync-groups.go
index 24e838c8f1ec64434a13652b36b18689ddb5a216..e1e054a663cad7d6613899ce87366ef79c4e1242 100644 (file)
@@ -16,6 +16,7 @@ import (
        "os"
        "strings"
 
+       "git.arvados.org/arvados.git/lib/cmd"
        "git.arvados.org/arvados.git/sdk/go/arvados"
 )
 
@@ -119,6 +120,7 @@ type ConfigParams struct {
        Path            string
        UserID          string
        Verbose         bool
+       CaseInsensitive bool
        ParentGroupUUID string
        ParentGroupName string
        SysUserUUID     string
@@ -141,9 +143,9 @@ func ParseFlags(config *ConfigParams) error {
   * 1st: Group name
   * 2nd: User identifier
   * 3rd (Optional): User permission on the group: can_read, can_write or can_manage. (Default: can_write)`
-               fmt.Fprintf(os.Stderr, "%s\n\n", usageStr)
-               fmt.Fprintf(os.Stderr, "Usage:\n%s [OPTIONS] <input-file.csv>\n\n", os.Args[0])
-               fmt.Fprintf(os.Stderr, "Options:\n")
+               fmt.Fprintf(flags.Output(), "%s\n\n", usageStr)
+               fmt.Fprintf(flags.Output(), "Usage:\n%s [OPTIONS] <input-file.csv>\n\n", os.Args[0])
+               fmt.Fprintf(flags.Output(), "Options:\n")
                flags.PrintDefaults()
        }
 
@@ -152,6 +154,10 @@ func ParseFlags(config *ConfigParams) error {
                "user-id",
                "email",
                "Attribute by which every user is identified. Valid values are: email and username.")
+       caseInsensitive := flags.Bool(
+               "case-insensitive",
+               false,
+               "Performs case insensitive matching on user IDs. Off by default.")
        verbose := flags.Bool(
                "verbose",
                false,
@@ -165,11 +171,9 @@ func ParseFlags(config *ConfigParams) error {
                "",
                "Use given group UUID as a parent for the remote groups. Should be owned by the system user. If not specified, a group named '"+config.ParentGroupName+"' will be used (and created if nonexistant).")
 
-       // Parse args; omit the first arg which is the command name
-       flags.Parse(os.Args[1:])
-
-       // Print version information if requested
-       if *getVersion {
+       if ok, code := cmd.ParseFlags(flags, os.Args[0], os.Args[1:], "input-file.csv", os.Stderr); !ok {
+               os.Exit(code)
+       } else if *getVersion {
                fmt.Printf("%s %s\n", os.Args[0], version)
                os.Exit(0)
        }
@@ -196,6 +200,7 @@ func ParseFlags(config *ConfigParams) error {
        config.ParentGroupUUID = *parentGroupUUID
        config.UserID = *userID
        config.Verbose = *verbose
+       config.CaseInsensitive = *caseInsensitive
 
        return nil
 }
@@ -299,7 +304,11 @@ func doMain(cfg *ConfigParams) error {
        }
        defer f.Close()
 
-       log.Printf("%s %s started. Using %q as users id and parent group UUID %q", os.Args[0], version, cfg.UserID, cfg.ParentGroupUUID)
+       iCaseLog := ""
+       if cfg.UserID == "username" && cfg.CaseInsensitive {
+               iCaseLog = " - username matching requested to be case-insensitive"
+       }
+       log.Printf("%s %s started. Using %q as users id and parent group UUID %q%s", os.Args[0], version, cfg.UserID, cfg.ParentGroupUUID, iCaseLog)
 
        // Get the complete user list to minimize API Server requests
        allUsers := make(map[string]arvados.User)
@@ -316,6 +325,12 @@ func doMain(cfg *ConfigParams) error {
                if err != nil {
                        return err
                }
+               if cfg.UserID == "username" && uID != "" && cfg.CaseInsensitive {
+                       uID = strings.ToLower(uID)
+                       if uuid, found := userIDToUUID[uID]; found {
+                               return fmt.Errorf("case insensitive collision for username %q between %q and %q", uID, u.UUID, uuid)
+                       }
+               }
                userIDToUUID[uID] = u.UUID
                if cfg.Verbose {
                        log.Printf("Seen user %q (%s)", u.Username, u.UUID)
@@ -415,6 +430,9 @@ func ProcessFile(
                        membersSkipped++
                        continue
                }
+               if cfg.UserID == "username" && cfg.CaseInsensitive {
+                       groupMember = strings.ToLower(groupMember)
+               }
                if !(groupPermission == "can_read" || groupPermission == "can_write" || groupPermission == "can_manage") {
                        log.Printf("Warning: 3rd field should be 'can_read', 'can_write' or 'can_manage'. Found: %q at line %d, skipping.", groupPermission, lineNo)
                        membersSkipped++
@@ -494,9 +512,7 @@ func GetAll(c *arvados.Client, res string, params arvados.ResourceListParams, pa
                if page.Len() == 0 {
                        break
                }
-               for _, i := range page.GetItems() {
-                       allItems = append(allItems, i)
-               }
+               allItems = append(allItems, page.GetItems()...)
                params.Offset += page.Len()
        }
        return allItems, nil
@@ -634,6 +650,9 @@ func GetRemoteGroups(cfg *ConfigParams, allUsers map[string]arvados.User) (remot
                        if err != nil {
                                return remoteGroups, groupNameToUUID, err
                        }
+                       if cfg.UserID == "username" && cfg.CaseInsensitive {
+                               memberID = strings.ToLower(memberID)
+                       }
                        membersSet[memberID] = u2gLinkSet[link.HeadUUID]
                }
                remoteGroups[group.UUID] = &GroupInfo{
@@ -714,9 +733,7 @@ func RemoveMemberLinksFromGroup(cfg *ConfigParams, user arvados.User, linkNames
                        userID, _ := GetUserID(user, cfg.UserID)
                        return fmt.Errorf("error getting links needed to remove user %q from group %q: %s", userID, group.Name, err)
                }
-               for _, link := range l {
-                       links = append(links, link)
-               }
+               links = append(links, l...)
        }
        for _, item := range links {
                link := item.(arvados.Link)