{"action":"created","comment":{"url":"https://api.github.com/repos/suffuse/go-suffuse/pulls/comments/34147723","id":34147723,"diff_hunk":"@@ -2,86 +2,138 @@ package suffuse\n \n import (\n   \"flag\"\n-  \"os\"\n-  \"bazil.org/fuse\"\n+  lg \"gopkg.in/inconshreveable/log15.v2\"\n )\n \n-type SfsOpts struct {\n-  Config, Mountpoint, ExcludeRegex, VolName string\n+type sfsOpts struct {\n+  printUsage func()\n+  Config, Mountpoint, VolName string\n   Scratch, Verbose, Debug bool\n   Args []string\n }\n \n-func UsageAndExit() {\n-  flag.Usage()\n-  os.Exit(2)\n+type SfsConfig struct {\n+  VolName string\n+  Config *Path\n+  Mountpoint Path\n+  LogLevel lg.Lvl\n+  Paths []Path\n }\n \n-func (opts SfsOpts) Create() (Sfs, error) {\n-  SetLogLevel(opts.GetLogLevel())\n-         mnt := opts.GetMountpoint()\n-  mount_opts := []fuse.MountOption { fuse.FSName(\"suffuse\") }\n-\n-  mount_opts = append(mount_opts, PlatformOptions()...)\n-  if opts.VolName != \"\" {\n-    mount_opts = append(mount_opts,\n-      fuse.LocalVolume(),\n-      fuse.VolumeName(opts.VolName),\n-    )\n+func CreateSfsConfig(args []string) (*SfsConfig, *SfsConfigError) {\n+\n+  opts, err := optsFromArgs(args)\n+  if err != nil { return nil, err }\n+\n+  err = validate(opts)\n+  if err != nil { return nil, err }\n+\n+  return configFromOpts(opts)\n+}\n+\n+func optsFromArgs(args []string) (*sfsOpts, *SfsConfigError) {\n+  fs := flag.NewFlagSet(\"suffuse\", flag.ContinueOnError)\n+\n+  fs.Usage = func () {\n+    Echoerr(\"Usage: %s <options> [path path ...]\\n\", args[0])\n+    fs.PrintDefaults()\n   }\n-  if opts.Config != \"\" {\n-    configFileOpts := ReadJsonFile(NewPath(opts.Config))\n-    Echoerr(\"%v\", configFileOpts)\n+\n+  opts := &sfsOpts{}\n+  opts.printUsage = fs.Usage\n+\n+  fs.StringVar(&opts.Config, \"c\", \"\", \"suffuse config file\")\n+  fs.StringVar(&opts.Mountpoint, \"m\", \"\", \"mount point\")\n+  fs.StringVar(&opts.VolName, \"n\", \"\", \"volume name (OSX only)\")\n+  fs.BoolVar(&opts.Scratch, \"t\", false, \"create scratch directory as mount point\")\n+  fs.BoolVar(&opts.Verbose, \"v\", false, \"log at INFO level\")\n+  fs.BoolVar(&opts.Debug, \"d\", false, \"log at DEBUG level\")\n+\n+  err := fs.Parse(args[1:])\n+  if err != nil {\n+    // Parse has already printed the problem and usage, there is no way to tell it not to do that\n+    return nil, &SfsConfigError{err: err.Error(), usage: nil}\n   }\n \n-  c, err := fuse.Mount(mnt.Path, mount_opts...)\n-  if err != nil { return Sfs{}, err }\n+  opts.Args = fs.Args()\n+  return opts, nil\n+}\n+\n+func validate(opts *sfsOpts) *SfsConfigError {\n+  exists := func (path string, msg string) *SfsConfigError {\n+    if (!NewPath(path).FileExists()) { return opts.newError(Sprintf(msg, path)) }\n+    return nil\n+  }\n \n   // Exactly one incoming path for the moment.\n   // Eventually more than one could mean a union mount.\n-  if len(opts.Args) != 1 { UsageAndExit() }\n+  if len(opts.Args) != 1 { return opts.newError(\"Suffuse currently accepts a single path\") }\n \n-  mfs := Sfs {\n-    Mountpoint : mnt,\n-    RootNode   : NewIdNode(NewPath(opts.Args[0])),\n-    Connection : c,\n-  }\n+  if err := exists(opts.Mountpoint, \"Mountpoint '%s' does not exist\" ); err != nil { return err }\n+  if err := exists(opts.Config    , \"Config file '%s' does not exist\"); err != nil && opts.Config != \"\" { return err }\n \n-  /** Start a goroutine which looks for INT/TERM and\n-   *  calls unmount on the filesystem. Otherwise ctrl-C\n-   *  leaves us with ghost mounts which outlive the process.\n-   */\n-  trap := func (sig os.Signal) {\n-    Echoerr(\"Caught %s - forcing unmount(2) of %s\\n\", sig, mfs.Mountpoint)\n-    mfs.Unmount()\n+  for _, path := range opts.Args {\n+    if err := exists(path, \"Path '%s' does not exist\"); err != nil { return err }\n   }\n-  TrapExit(trap)\n-  return mfs, nil\n+\n+  return nil\n }\n \n-func (opts SfsOpts) GetMountpoint() Path {\n-  switch {\n-    case opts.Scratch          : return ScratchDir()\n-    case opts.Mountpoint != \"\" : return NewPath(opts.Mountpoint)\n-    default                    : UsageAndExit() ; return Path{}\n+func configFromOpts(opts *sfsOpts) (*SfsConfig, *SfsConfigError) {\n+\n+  determineMountPoint := func() (Path, *SfsConfigError) {\n+    switch {\n+      case opts.Scratch          : return ScratchDir(), nil\n+      case opts.Mountpoint != \"\" : return NewPath(opts.Mountpoint), nil\n+      default                    : return Path{}, opts.newError(\"Mountpoint can not be empty if the scratch flag is false\")\n+    }\n+  }\n+\n+  determineLogLevel := func() lg.Lvl {\n+    switch {\n+      case opts.Debug   : return lg.LvlDebug\n+      case opts.Verbose : return lg.LvlInfo\n+      default           : return lg.LvlWarn\n+    }\n+  }\n+\n+  determineConfig := func() *Path {\n+    if opts.Config == \"\" {\n+      return nil\n+    } else {\n+      var c = NewPath(opts.Config)\n+      return &c\n+    }\n   }","path":"suffuse/opts.go","position":149,"original_position":149,"commit_id":"b85fba1ad50a62aea6e2879df5cfdd2c470595fb","original_commit_id":"b85fba1ad50a62aea6e2879df5cfdd2c470595fb","user":{"login":"EECOLOR","id":1486362,"avatar_url":"https://avatars.githubusercontent.com/u/1486362?v=3","gravatar_id":"","url":"https://api.github.com/users/EECOLOR","html_url":"https://github.com/EECOLOR","followers_url":"https://api.github.com/users/EECOLOR/followers","following_url":"https://api.github.com/users/EECOLOR/following{/other_user}","gists_url":"https://api.github.com/users/EECOLOR/gists{/gist_id}","starred_url":"https://api.github.com/users/EECOLOR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EECOLOR/subscriptions","organizations_url":"https://api.github.com/users/EECOLOR/orgs","repos_url":"https://api.github.com/users/EECOLOR/repos","events_url":"https://api.github.com/users/EECOLOR/events{/privacy}","received_events_url":"https://api.github.com/users/EECOLOR/received_events","type":"User","site_admin":false},"body":"Yeah, that sounds great. I will go and add that as soon as I am home.","created_at":"2015-07-08T13:40:25Z","updated_at":"2015-07-08T13:40:25Z","html_url":"https://github.com/suffuse/go-suffuse/pull/20#discussion_r34147723","pull_request_url":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20","_links":{"self":{"href":"https://api.github.com/repos/suffuse/go-suffuse/pulls/comments/34147723"},"html":{"href":"https://github.com/suffuse/go-suffuse/pull/20#discussion_r34147723"},"pull_request":{"href":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20"}}},"pull_request":{"url":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20","id":39411820,"html_url":"https://github.com/suffuse/go-suffuse/pull/20","diff_url":"https://github.com/suffuse/go-suffuse/pull/20.diff","patch_url":"https://github.com/suffuse/go-suffuse/pull/20.patch","issue_url":"https://api.github.com/repos/suffuse/go-suffuse/issues/20","number":20,"state":"open","locked":false,"title":"Improved separation of concerns for `SfsOpts`","user":{"login":"EECOLOR","id":1486362,"avatar_url":"https://avatars.githubusercontent.com/u/1486362?v=3","gravatar_id":"","url":"https://api.github.com/users/EECOLOR","html_url":"https://github.com/EECOLOR","followers_url":"https://api.github.com/users/EECOLOR/followers","following_url":"https://api.github.com/users/EECOLOR/following{/other_user}","gists_url":"https://api.github.com/users/EECOLOR/gists{/gist_id}","starred_url":"https://api.github.com/users/EECOLOR/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/EECOLOR/subscriptions","organizations_url":"https://api.github.com/users/EECOLOR/orgs","repos_url":"https://api.github.com/users/EECOLOR/repos","events_url":"https://api.github.com/users/EECOLOR/events{/privacy}","received_events_url":"https://api.github.com/users/EECOLOR/received_events","type":"User","site_admin":false},"body":"- Moved the responsibility of reporting errors outside of `SfsOpts`\r\n- Renamed `Args` to `Paths` which reflects intention a bit better\r\n- `ParseSfsOpts` now takes an array of strings and returns (potentially) an error\r\n- Improved general error reporting for the creation of options (options are validated)\r\n- Moved the creation of a `Sfs` to `sfs.go`\r\n- Added a `FileExists` utility method","created_at":"2015-07-07T20:17:14Z","updated_at":"2015-07-08T13:40:25Z","closed_at":null,"merged_at":null,"merge_commit_sha":"48240f5259fea278fe33e42c6147b3f0b2bb26dd","assignee":{"login":"paulp","id":9135,"avatar_url":"https://avatars.githubusercontent.com/u/9135?v=3","gravatar_id":"","url":"https://api.github.com/users/paulp","html_url":"https://github.com/paulp","followers_url":"https://api.github.com/users/paulp/followers","following_url":"https://api.github.com/users/paulp/following{/other_user}","gists_url":"https://api.github.com/users/paulp/gists{/gist_id}","starred_url":"https://api.github.com/users/paulp/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/paulp/subscriptions","organizations_url":"https://api.github.com/users/paulp/orgs","repos_url":"https://api.github.com/users/paulp/repos","events_url":"https://api.github.com/users/paulp/events{/privacy}","received_events_url":"https://api.github.com/users/paulp/received_events","type":"User","site_admin":false},"milestone":null,"commits_url":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20/commits","review_comments_url":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20/comments","review_comment_url":"https://api.github.com/repos/suffuse/go-suffuse/pulls/comments{/number}","comments_url":"https://api.github.com/repos/suffuse/go-suffuse/issues/20/comments","statuses_url":"https://api.github.com/repos/suffuse/go-suffuse/statuses/b85fba1ad50a62aea6e2879df5cfdd2c470595fb","head":{"label":"suffuse:refactoring_opts","ref":"refactoring_opts","sha":"b85fba1ad50a62aea6e2879df5cfdd2c470595fb","user":{"login":"suffuse","id":10980633,"avatar_url":"https://avatars.githubusercontent.com/u/10980633?v=3","gravatar_id":"","url":"https://api.github.com/users/suffuse","html_url":"https://github.com/suffuse","followers_url":"https://api.github.com/users/suffuse/followers","following_url":"https://api.github.com/users/suffuse/following{/other_user}","gists_url":"https://api.github.com/users/suffuse/gists{/gist_id}","starred_url":"https://api.github.com/users/suffuse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/suffuse/subscriptions","organizations_url":"https://api.github.com/users/suffuse/orgs","repos_url":"https://api.github.com/users/suffuse/repos","events_url":"https://api.github.com/users/suffuse/events{/privacy}","received_events_url":"https://api.github.com/users/suffuse/received_events","type":"Organization","site_admin":false},"repo":{"id":38389488,"name":"go-suffuse","full_name":"suffuse/go-suffuse","owner":{"login":"suffuse","id":10980633,"avatar_url":"https://avatars.githubusercontent.com/u/10980633?v=3","gravatar_id":"","url":"https://api.github.com/users/suffuse","html_url":"https://github.com/suffuse","followers_url":"https://api.github.com/users/suffuse/followers","following_url":"https://api.github.com/users/suffuse/following{/other_user}","gists_url":"https://api.github.com/users/suffuse/gists{/gist_id}","starred_url":"https://api.github.com/users/suffuse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/suffuse/subscriptions","organizations_url":"https://api.github.com/users/suffuse/orgs","repos_url":"https://api.github.com/users/suffuse/repos","events_url":"https://api.github.com/users/suffuse/events{/privacy}","received_events_url":"https://api.github.com/users/suffuse/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/suffuse/go-suffuse","description":"go client for suffuse","fork":false,"url":"https://api.github.com/repos/suffuse/go-suffuse","forks_url":"https://api.github.com/repos/suffuse/go-suffuse/forks","keys_url":"https://api.github.com/repos/suffuse/go-suffuse/keys{/key_id}","collaborators_url":"https://api.github.com/repos/suffuse/go-suffuse/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/suffuse/go-suffuse/teams","hooks_url":"https://api.github.com/repos/suffuse/go-suffuse/hooks","issue_events_url":"https://api.github.com/repos/suffuse/go-suffuse/issues/events{/number}","events_url":"https://api.github.com/repos/suffuse/go-suffuse/events","assignees_url":"https://api.github.com/repos/suffuse/go-suffuse/assignees{/user}","branches_url":"https://api.github.com/repos/suffuse/go-suffuse/branches{/branch}","tags_url":"https://api.github.com/repos/suffuse/go-suffuse/tags","blobs_url":"https://api.github.com/repos/suffuse/go-suffuse/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/suffuse/go-suffuse/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/suffuse/go-suffuse/git/refs{/sha}","trees_url":"https://api.github.com/repos/suffuse/go-suffuse/git/trees{/sha}","statuses_url":"https://api.github.com/repos/suffuse/go-suffuse/statuses/{sha}","languages_url":"https://api.github.com/repos/suffuse/go-suffuse/languages","stargazers_url":"https://api.github.com/repos/suffuse/go-suffuse/stargazers","contributors_url":"https://api.github.com/repos/suffuse/go-suffuse/contributors","subscribers_url":"https://api.github.com/repos/suffuse/go-suffuse/subscribers","subscription_url":"https://api.github.com/repos/suffuse/go-suffuse/subscription","commits_url":"https://api.github.com/repos/suffuse/go-suffuse/commits{/sha}","git_commits_url":"https://api.github.com/repos/suffuse/go-suffuse/git/commits{/sha}","comments_url":"https://api.github.com/repos/suffuse/go-suffuse/comments{/number}","issue_comment_url":"https://api.github.com/repos/suffuse/go-suffuse/issues/comments{/number}","contents_url":"https://api.github.com/repos/suffuse/go-suffuse/contents/{+path}","compare_url":"https://api.github.com/repos/suffuse/go-suffuse/compare/{base}...{head}","merges_url":"https://api.github.com/repos/suffuse/go-suffuse/merges","archive_url":"https://api.github.com/repos/suffuse/go-suffuse/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/suffuse/go-suffuse/downloads","issues_url":"https://api.github.com/repos/suffuse/go-suffuse/issues{/number}","pulls_url":"https://api.github.com/repos/suffuse/go-suffuse/pulls{/number}","milestones_url":"https://api.github.com/repos/suffuse/go-suffuse/milestones{/number}","notifications_url":"https://api.github.com/repos/suffuse/go-suffuse/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/suffuse/go-suffuse/labels{/name}","releases_url":"https://api.github.com/repos/suffuse/go-suffuse/releases{/id}","created_at":"2015-07-01T19:02:43Z","updated_at":"2015-07-01T21:45:06Z","pushed_at":"2015-07-08T12:34:19Z","git_url":"git://github.com/suffuse/go-suffuse.git","ssh_url":"git@github.com:suffuse/go-suffuse.git","clone_url":"https://github.com/suffuse/go-suffuse.git","svn_url":"https://github.com/suffuse/go-suffuse","homepage":null,"size":529,"stargazers_count":2,"watchers_count":2,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":3,"forks":1,"open_issues":3,"watchers":2,"default_branch":"master"}},"base":{"label":"suffuse:master","ref":"master","sha":"81622a575b7cce64a4d40a263d57521fc47544ad","user":{"login":"suffuse","id":10980633,"avatar_url":"https://avatars.githubusercontent.com/u/10980633?v=3","gravatar_id":"","url":"https://api.github.com/users/suffuse","html_url":"https://github.com/suffuse","followers_url":"https://api.github.com/users/suffuse/followers","following_url":"https://api.github.com/users/suffuse/following{/other_user}","gists_url":"https://api.github.com/users/suffuse/gists{/gist_id}","starred_url":"https://api.github.com/users/suffuse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/suffuse/subscriptions","organizations_url":"https://api.github.com/users/suffuse/orgs","repos_url":"https://api.github.com/users/suffuse/repos","events_url":"https://api.github.com/users/suffuse/events{/privacy}","received_events_url":"https://api.github.com/users/suffuse/received_events","type":"Organization","site_admin":false},"repo":{"id":38389488,"name":"go-suffuse","full_name":"suffuse/go-suffuse","owner":{"login":"suffuse","id":10980633,"avatar_url":"https://avatars.githubusercontent.com/u/10980633?v=3","gravatar_id":"","url":"https://api.github.com/users/suffuse","html_url":"https://github.com/suffuse","followers_url":"https://api.github.com/users/suffuse/followers","following_url":"https://api.github.com/users/suffuse/following{/other_user}","gists_url":"https://api.github.com/users/suffuse/gists{/gist_id}","starred_url":"https://api.github.com/users/suffuse/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/suffuse/subscriptions","organizations_url":"https://api.github.com/users/suffuse/orgs","repos_url":"https://api.github.com/users/suffuse/repos","events_url":"https://api.github.com/users/suffuse/events{/privacy}","received_events_url":"https://api.github.com/users/suffuse/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/suffuse/go-suffuse","description":"go client for suffuse","fork":false,"url":"https://api.github.com/repos/suffuse/go-suffuse","forks_url":"https://api.github.com/repos/suffuse/go-suffuse/forks","keys_url":"https://api.github.com/repos/suffuse/go-suffuse/keys{/key_id}","collaborators_url":"https://api.github.com/repos/suffuse/go-suffuse/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/suffuse/go-suffuse/teams","hooks_url":"https://api.github.com/repos/suffuse/go-suffuse/hooks","issue_events_url":"https://api.github.com/repos/suffuse/go-suffuse/issues/events{/number}","events_url":"https://api.github.com/repos/suffuse/go-suffuse/events","assignees_url":"https://api.github.com/repos/suffuse/go-suffuse/assignees{/user}","branches_url":"https://api.github.com/repos/suffuse/go-suffuse/branches{/branch}","tags_url":"https://api.github.com/repos/suffuse/go-suffuse/tags","blobs_url":"https://api.github.com/repos/suffuse/go-suffuse/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/suffuse/go-suffuse/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/suffuse/go-suffuse/git/refs{/sha}","trees_url":"https://api.github.com/repos/suffuse/go-suffuse/git/trees{/sha}","statuses_url":"https://api.github.com/repos/suffuse/go-suffuse/statuses/{sha}","languages_url":"https://api.github.com/repos/suffuse/go-suffuse/languages","stargazers_url":"https://api.github.com/repos/suffuse/go-suffuse/stargazers","contributors_url":"https://api.github.com/repos/suffuse/go-suffuse/contributors","subscribers_url":"https://api.github.com/repos/suffuse/go-suffuse/subscribers","subscription_url":"https://api.github.com/repos/suffuse/go-suffuse/subscription","commits_url":"https://api.github.com/repos/suffuse/go-suffuse/commits{/sha}","git_commits_url":"https://api.github.com/repos/suffuse/go-suffuse/git/commits{/sha}","comments_url":"https://api.github.com/repos/suffuse/go-suffuse/comments{/number}","issue_comment_url":"https://api.github.com/repos/suffuse/go-suffuse/issues/comments{/number}","contents_url":"https://api.github.com/repos/suffuse/go-suffuse/contents/{+path}","compare_url":"https://api.github.com/repos/suffuse/go-suffuse/compare/{base}...{head}","merges_url":"https://api.github.com/repos/suffuse/go-suffuse/merges","archive_url":"https://api.github.com/repos/suffuse/go-suffuse/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/suffuse/go-suffuse/downloads","issues_url":"https://api.github.com/repos/suffuse/go-suffuse/issues{/number}","pulls_url":"https://api.github.com/repos/suffuse/go-suffuse/pulls{/number}","milestones_url":"https://api.github.com/repos/suffuse/go-suffuse/milestones{/number}","notifications_url":"https://api.github.com/repos/suffuse/go-suffuse/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/suffuse/go-suffuse/labels{/name}","releases_url":"https://api.github.com/repos/suffuse/go-suffuse/releases{/id}","created_at":"2015-07-01T19:02:43Z","updated_at":"2015-07-01T21:45:06Z","pushed_at":"2015-07-08T12:34:19Z","git_url":"git://github.com/suffuse/go-suffuse.git","ssh_url":"git@github.com:suffuse/go-suffuse.git","clone_url":"https://github.com/suffuse/go-suffuse.git","svn_url":"https://github.com/suffuse/go-suffuse","homepage":null,"size":529,"stargazers_count":2,"watchers_count":2,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"open_issues_count":3,"forks":1,"open_issues":3,"watchers":2,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20"},"html":{"href":"https://github.com/suffuse/go-suffuse/pull/20"},"issue":{"href":"https://api.github.com/repos/suffuse/go-suffuse/issues/20"},"comments":{"href":"https://api.github.com/repos/suffuse/go-suffuse/issues/20/comments"},"review_comments":{"href":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20/comments"},"review_comment":{"href":"https://api.github.com/repos/suffuse/go-suffuse/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/suffuse/go-suffuse/pulls/20/commits"},"statuses":{"href":"https://api.github.com/repos/suffuse/go-suffuse/statuses/b85fba1ad50a62aea6e2879df5cfdd2c470595fb"}}}}