Commits

Paul Ruane  committed ddac573

Improved help.
Added 'merge' command.

  • Participants
  • Parent commits 62c5fc6
  • Tags semver, v0.0.1

Comments (0)

Files changed (15)

-V1
+V0.1
 
 o Automatic database creation.                          [ ]
+o Default database directory overriding                 [X]
+o Mount the VFS.                                        [X]
+    >tmsu mount SOMEDIR
+o Unmount the VFS.                                      [X]
+    >tmsu unmount SOMEDIR
+o Add files to the VFS.                                 [X]
+    >tmsu add REALFILE...
+o Remove files from the VFS.                            [X]
+    >tmsu remove REALFILE...
+o Add one or more tags to a file.                       [X]
+    >tmsu tag REALFILE tag...
+o Remove one or more tags from a file.                  [X]
+    >tmsu untag REALFILE TAG...
+o List all tags                                         [X]
+    >tmsu tags
+o List tags for a particular file.                      [X]
+    >tmsu tags REALFILE...
+o View files for single tag.                            [X]
+    >ls mountpoint/tags/tag1
+o View files with multiple tags
+    >ls mountpoint/tags/tag1/tag2/...
+o View untagged files.                                  [ ]
+    >ls untagged
+o Rename tag.                                           [X]
+    >tmsu rename OLD NEW
+o Rename tag (merge with existing)                      [X]
+    >tmsu rename OLD NEW
+o Database import/export
 
-o Mount the VFS.                                        [X]
-    >tmsu mount somedir
-o Unmount the VFS.                                      [X]
-    >tmsu unmount
-
-o Add files to the VFS.                                 [X]
-    >tmsu add realfile
-o Remove files from the VFS.                            [X]
-    >tmsu remove realfile
-o Add one or more tags to a file.                       [X]
-    >tmsu tag file tag1 tag2
-o Remove one or more tags from a file.                  [ ]
-    >tmsu untag file tag1 tag2
-    >tmsu tag file -tag1 -tag2
-
-o List tags for a particular file.                      [ ]
-    >tmsu tags realfile
-
-o View files for single tag.                            [X]
-    >cd tags/tag1; ls
-o View files for multiple tags (AND operation only).    [X]
-    >cd tags/tag1/tag2/tag3; ls
-o View untagged files.                                  [ ]
-    >cd untagged; ls
-
-V2
+V0.2
 
 o Duplicate file handling.                              [ ]
     TODO
 o View files for multiple tags (OR operation).          [ ]
     >cd tags/tag1+tag2+tag3
 
-V3
+V0.3
 
 o Custom views                                          [ ]
     >tmsu view somename "(tag1 or tag2) and tag3"; ls views/somename

File src/tmsu/Makefile

 		commands/tag.go \
 		commands/untag.go \
 		commands/rename.go \
+		commands/merge.go \
 		database.go \
 		fusefs.go \
 		tag.go \

File src/tmsu/command.go

 
 type Command interface {
     Name() string
-    Description() string
+    Summary() string
+    Help() string
     Exec(args []string) error
 }

File src/tmsu/commands/add.go

     return "add"
 }
 
-func (this AddCommand) Description() string {
+func (this AddCommand) Summary() string {
     return "adds a file without applying any tags"
 }
 
+func (this AddCommand) Help() string {
+    return `  tmsu add FILE...
+
+Adds the files specified without applying any tags.`
+}
+
 func (this AddCommand) Exec(args []string) error {
     if len(args) < 1 { return errors.New("At least one file to add must be specified.") }
 
 
             //TODO contents have changed, update file-path
             log.Fatalf("Not implemented.")
-        default:
-            fmt.Printf("File '%v' is already added.\n", path)
     }
 
     return file, filePath, nil

File src/tmsu/commands/help.go

     return "help"
 }
 
-func (this HelpCommand) Description() string {
+func (this HelpCommand) Summary() string {
     return "lists commands or provides help for a particular command"
 }
 
+func (this HelpCommand) Help() string {
+    return `  tmsu help          lists commands
+  tmsu help COMMAND  shows help for COMMAND
+
+Shows command summary or, when a command is specified, detailed help for that command.`
+}
+
 func (this HelpCommand) Exec(args []string) error {
-    fmt.Println("tmsu")
+    switch len(args) {
+        case 0:
+            this.overview()
+        default:
+            this.commandHelp(args[0])
+    }
+
+    return nil
+}
+
+// implementation
+
+func (this HelpCommand) overview() {
+    fmt.Println("tmsu v0.1 (alpha)")
     fmt.Println()
 
     var maxWidth uint = 0
     }
 
     for _, command := range commands {
-        fmt.Printf("  %-" + strconv.Uitoa(maxWidth) + "v  %v\n", command.Name(), command.Description())
+        fmt.Printf("  %-" + strconv.Uitoa(maxWidth) + "v  %v\n", command.Name(), command.Summary())
     }
 
     fmt.Println()
     fmt.Println("Copyright (C) 2011 Paul Ruane")
+}
 
-    return nil
+func (this HelpCommand) commandHelp(commandName string) {
+    command := commands[commandName]
+    if command == nil {
+        fmt.Printf("No such command '%v'.\n", commandName)
+        return
+    }
+
+    fmt.Println(command.Help())
 }

File src/tmsu/commands/merge.go

+package main
+
+import (
+           "errors"
+           "log"
+       )
+
+type MergeCommand struct {}
+
+func (this MergeCommand) Name() string {
+    return "merge"
+}
+
+func (this MergeCommand) Summary() string {
+    return "merges a tag with another"
+}
+
+func (this MergeCommand) Help() string {
+    return `  tmsu merge SRC DEST
+        
+Merges SRC into DEST resulting in a single tag of name DEST.`
+}
+
+func (this MergeCommand) Exec(args []string) error {
+    db, error := OpenDatabase(databasePath())
+    if error != nil { log.Fatalf("Could not open database: %v", error) }
+    defer db.Close()
+
+    sourceTagName := args[0]
+    destTagName := args[1]
+
+    sourceTag, error := db.TagByName(sourceTagName)
+    if error != nil { return error }
+    if sourceTag == nil { return errors.New("No such tag '" + sourceTagName + "'.") }
+
+    destTag, error := db.TagByName(destTagName)
+    if error != nil { return error }
+    if destTag == nil { return errors.New("No such tag '" + destTagName + "'.") }
+
+    error = db.MigrateFileTags(sourceTag.Id, destTag.Id)
+    if error != nil { return error }
+
+    error = db.DeleteTag(sourceTag.Id)
+    if error != nil { return error }
+
+    return nil
+}

File src/tmsu/commands/mount.go

     return "mount"
 }
 
-func (this MountCommand) Description() string {
+func (this MountCommand) Summary() string {
     return "mounts the virtual file-system"
 }
 
+func (this MountCommand) Help() string {
+    return `  tmsu mount MOUNTPOINT
+
+Mounts the virtual file-system (VFS) at the mountpoint directory specified.
+The default database at '$HOME/.tmsu/db' will be mounted unless overridden with the 'TMSU_DB' environment variable.`
+}
+
 func (this MountCommand) Exec(args []string) error {
     if (len(args) == 0) { errors.New("Mountpoint not specified.") }
 

File src/tmsu/commands/remove.go

     return "remove"
 }
 
-func (this RemoveCommand) Description() string {
+func (this RemoveCommand) Summary() string {
     return "removes a previously added file"
 }
 
+func (this RemoveCommand) Help() string {
+    return `  tmsu remove FILE...
+
+Removes the specified file(s).`
+}
+
 func (this RemoveCommand) Exec(args []string) error {
     if len(args) < 1 { return errors.New("At least one file to remove must be specified.") }
 

File src/tmsu/commands/rename.go

 
 import (
            "errors"
+           "fmt"
            "log"
        )
 
     return "rename"
 }
 
-func (this RenameCommand) Description() string {
+func (this RenameCommand) Summary() string {
     return "renames a tag"
 }
 
+func (this RenameCommand) Help() string {
+    return `  tmsu rename OLD NEW
+
+Renames a tag from OLD to NEW.
+
+Attempting to rename a tag with a new name for which a tag already exists will result in an error.
+To merge tags use the 'merge' command instead.`
+}
+
 func (this RenameCommand) Exec(args []string) error {
     db, error := OpenDatabase(databasePath())
     if error != nil { log.Fatalf("Could not open database: %v", error) }
     defer db.Close()
 
-    currentName := args[0]
-    newName := args[1]
+    sourceTagName := args[0]
+    destTagName := args[1]
 
-    tag, error := db.TagByName(currentName)
+    sourceTag, error := db.TagByName(sourceTagName)
     if error != nil { return error }
-    if tag == nil { errors.New("No such tag '" + currentName + "'.") }
+    if sourceTag == nil { return errors.New(fmt.Sprintf("No such tag '%v'.", sourceTagName)) }
 
-    newTag, error := db.TagByName(newName)
+    destTag, error := db.TagByName(destTagName)
     if error != nil { return error }
+    if destTag != nil { return errors.New(fmt.Sprintf("A tag with name '%v' already exists.", destTagName)) }
 
-    //TODO only merge if flag set
-
-    if newTag == nil {
-        _, error = db.RenameTag(tag.Id, newName)
-        if error != nil { return error }
-    } else {
-        error = db.MigrateFileTags(tag.Id, newTag.Id)
-        if error != nil { return error }
-
-        error = db.DeleteTag(tag.Id)
-        if error != nil { return error }
-    }
+    _, error = db.RenameTag(sourceTag.Id, destTagName)
+    if error != nil { return error }
 
     return nil
 }

File src/tmsu/commands/tag.go

     return "tag"
 }
 
-func (this TagCommand) Description() string {
+func (this TagCommand) Summary() string {
     return "applies one or more tags to a file"
 }
 
+func (this TagCommand) Help() string {
+    return `  tmsu tag FILE TAG...
+
+Tags the file FILE with the tag(s) specified.`
+}
+
 func (this TagCommand) Exec(args []string) error {
     if len(args) < 2 { return errors.New("File to tag and tags to apply must be specified.") }
 
     if fileTag == nil {
         _, error := db.AddFileTag(fileId, tag.Id)
         if error != nil { return nil, nil, error }
-    } else {
-        fmt.Printf("File '%v' is already tagged '%v'.\n", path, tagName)
     }
 
     return tag, fileTag, nil

File src/tmsu/commands/tags.go

     return "tags"
 }
 
-func (this TagsCommand) Description() string {
+func (this TagsCommand) Summary() string {
     return "lists all tags or tags applied to a file or files"
 }
 
+func (this TagsCommand) Help() string {
+    return `  tmsu tags
+  tmsu tags FILE...
+
+Without any filenames, shows the complete list of tags.
+
+With a single filename, lists the tags applied to that file.
+
+With multiple filenames, lists the names of these that have tags applied and the list of applied tags.`
+}
+
 func (this TagsCommand) Exec(args []string) error {
     db, error := OpenDatabase(databasePath())
     if error != nil { log.Fatalf("Could not open database: %v", error) }
                 tags, error := this.tagsForPath(db, path)
                 if error != nil { log.Fatalf("Could not retrieve tags for '%v': %v", path, error) }
 
-                if len(tags) > 0 {
-                    fmt.Println(path)
+                fmt.Println(path)
 
-                    for _, tag := range tags {
-                        fmt.Println("  " + tag.Name)
-                    }
+                for _, tag := range tags {
+                    fmt.Println("  " + tag.Name)
                 }
             }
     }

File src/tmsu/commands/unmount.go

     return "unmount"
 }
 
-func (this UnmountCommand) Description() string {
+func (this UnmountCommand) Summary() string {
     return "unmounts the virtual file-system"
 }
 
+func (this UnmountCommand) Help() string {
+    return `  tags unount MOUNTPOINT
+
+Unmounts a previously mounted virtual file-system at the mountpoint specified.`
+}
+
 func (this UnmountCommand) Exec(args []string) error {
     if len(args) < 1 { errors.New("Path to unmount not speciified.") }
 

File src/tmsu/commands/untag.go

     return "untag"
 }
 
-func (this UntagCommand) Description() string {
+func (this UntagCommand) Summary() string {
     return "removes tags from a file"
 }
 
+func (this UntagCommand) Help() string {
+    return `  tmsu untag FILE TAG...
+
+Disassociates the specified file FILE with the tag(s) specified.`
+}
+
 func (this UntagCommand) Exec(args []string) error {
     if len(args) < 2 { return errors.New("File to untag and tags to remove must be specified.") }
 

File src/tmsu/fusefs.go

     name := path[pathLength - 1]
 
     filePathId, error := parseFilePathId(name)
-    if error != nil { log.Fatalf("Could not parse file-path identifier: %v", error) }
+    if error != nil { return nil, fuse.ENOENT }
 
     if filePathId == 0 { return &os.FileInfo{ Mode: fuse.S_IFDIR | 0755 }, fuse.OK }
 

File src/tmsu/main.go

 
 import (
 	       "flag"
-	       "fmt"
 	       "log"
        )
 
                                  TagCommand{},
                                  UntagCommand{},
                                  RenameCommand{},
+                                 MergeCommand{},
                              }
 
     commands = make(map [string] Command, len(commandArray))
     for _, command := range commandArray { commands[command.Name()] = command }
 
 	flag.Parse()
-    if flag.NArg() == 0 { showUsage() }
-    commandName := flag.Arg(0)
-    args := flag.Args()[1:]
+
+	var commandName string
+    if flag.NArg() > 0 {
+        commandName = flag.Arg(0)
+    } else {
+        commandName = "help"
+    }
+
+    var args []string
+    if flag.NArg() > 1 {
+        args = flag.Args()[1:]
+    } else {
+        args = []string {}
+    }
 
     command := commands[commandName]
     if command == nil { log.Fatalf("No such command, '%v'.", commandName) }
     error := command.Exec(args)
     if error != nil { log.Fatal(error) }
 }
-
-// other stuff
-
-func showUsage() {
-    fmt.Println("usage: tmsu <command> [<args>]")
-    fmt.Println()
-    fmt.Println("commands:")
-    fmt.Println()
-    fmt.Println(" help       list commands or provide help for a given command")
-    fmt.Println(" mount      mounts the file-system")
-    fmt.Println(" add        add a file without applying tags")
-    fmt.Println(" remove     remove a file")
-    fmt.Println(" tag        add a file (if necessary) and apply tags")
-    fmt.Println(" untag      disassociate a file with tags")
-    fmt.Println(" tags       list all tags or tags for a given file")
-    fmt.Println(" dupes      list duplicate files")
-}
-