{"action":"created","comment":{"url":"https://api.github.com/repos/restic/restic/pulls/comments/34952775","id":34952775,"diff_hunk":"@@ -0,0 +1,301 @@\n+// +build !openbsd\n+\n+package main\n+\n+import (\n+\t\"encoding/binary\"\n+\t\"fmt\"\n+\t\"os\"\n+\t\"time\"\n+\n+\t\"golang.org/x/net/context\"\n+\n+\t\"github.com/restic/restic\"\n+\t\"github.com/restic/restic/backend\"\n+\t\"github.com/restic/restic/crypto\"\n+\t\"github.com/restic/restic/pack\"\n+\t\"github.com/restic/restic/repository\"\n+\n+\t\"bazil.org/fuse\"\n+\t\"bazil.org/fuse/fs\"\n+)\n+\n+type CmdMount struct {\n+\tglobal *GlobalOptions\n+\tready  chan struct{}\n+}\n+\n+func init() {\n+\t_, err := parser.AddCommand(\"mount\",\n+\t\t\"mount a repository\",\n+\t\t\"The mount command mounts a repository read-only to a given directory\",\n+\t\t&CmdMount{\n+\t\t\tglobal: &globalOpts,\n+\t\t\tready:  make(chan struct{}, 1),\n+\t\t})\n+\tif err != nil {\n+\t\tpanic(err)\n+\t}\n+}\n+\n+func (cmd CmdMount) Usage() string {\n+\treturn \"MOUNTPOINT\"\n+}\n+\n+func (cmd CmdMount) Execute(args []string) error {\n+\tif len(args) == 0 {\n+\t\treturn fmt.Errorf(\"wrong number of parameters, Usage: %s\", cmd.Usage())\n+\t}\n+\n+\trepo, err := cmd.global.OpenRepository()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\terr = repo.LoadIndex()\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tmountpoint := args[0]\n+\tif _, err := os.Stat(mountpoint); err != nil {\n+\t\tif os.IsNotExist(err) {\n+\t\t\tcmd.global.Verbosef(\"Mountpoint %s doesn't exist, creating it\\n\", mountpoint)\n+\t\t\terr = os.Mkdir(mountpoint, os.ModeDir|0700)\n+\t\t\tif err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t}\n+\t}\n+\tc, err := fuse.Mount(\n+\t\tmountpoint,\n+\t\tfuse.ReadOnly(),\n+\t\tfuse.FSName(\"restic\"),\n+\t)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\troot := fs.Tree{}\n+\troot.Add(\"snapshots\", &snapshots{\n+\t\trepo:           repo,\n+\t\tknownSnapshots: make(map[string]*restic.Snapshot),\n+\t})\n+\n+\tcmd.global.Printf(\"Now serving %s under %s\\n\", repo.Backend().Location(), mountpoint)\n+\tcmd.global.Printf(\"Don't forget to umount after quitting !\\n\")\n+\n+\tcmd.ready <- struct{}{}\n+\n+\terr = fs.Serve(c, &root)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\t<-c.Ready\n+\treturn c.MountError\n+}\n+\n+// These lines statically ensure that a *snapshots implement the given\n+// interfaces; a misplaced refactoring of the implementation that breaks\n+// the interface will be catched by the compiler\n+var _ = fs.HandleReadDirAller(&snapshots{})\n+var _ = fs.NodeStringLookuper(&snapshots{})\n+\n+type snapshots struct {\n+\trepo *repository.Repository\n+\n+\t// snapshot timestamp -> snapshot\n+\tknownSnapshots map[string]*restic.Snapshot\n+}\n+\n+func (sn *snapshots) Attr(ctx context.Context, a *fuse.Attr) error {\n+\ta.Inode = 0\n+\ta.Mode = os.ModeDir | 0555\n+\treturn nil\n+}\n+\n+func (sn *snapshots) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {\n+\tret := make([]fuse.Dirent, 0)\n+\tfor id := range sn.repo.List(backend.Snapshot, ctx.Done()) {\n+\t\tsnapshot, err := restic.LoadSnapshot(sn.repo, id)\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t\tsn.knownSnapshots[snapshot.Time.Format(time.RFC3339)] = snapshot\n+\t\tret = append(ret, fuse.Dirent{\n+\t\t\tInode: binary.BigEndian.Uint64(id[:8]),\n+\t\t\tType:  fuse.DT_Dir,\n+\t\t\tName:  snapshot.Time.Format(time.RFC3339),\n+\t\t})\n+\t}\n+\n+\treturn ret, nil\n+}\n+\n+func (sn *snapshots) Lookup(ctx context.Context, name string) (fs.Node, error) {\n+\tif _, ok := sn.knownSnapshots[name]; !ok {\n+\t\t// At least this snapshot is not cached. We use this opportunity to\n+\t\t// load all missing snapshots\n+\t\tfor id := range sn.repo.List(backend.Snapshot, ctx.Done()) {\n+\t\t\tsnapshot, err := restic.LoadSnapshot(sn.repo, id)\n+\t\t\tif err != nil {\n+\t\t\t\treturn nil, err\n+\t\t\t}\n+\t\t\tsnapshotName := snapshot.Time.Format(time.RFC3339)\n+\t\t\tsn.knownSnapshots[snapshotName] = snapshot\n+\t\t\tbreak\n+\t\t}\n+\t}\n+\n+\tsnapshot := sn.knownSnapshots[name]\n+\ttree, err := restic.LoadTree(sn.repo, snapshot.Tree)\n+\tif err != nil {\n+\t\treturn nil, err\n+\t}\n+\treturn &dir{\n+\t\trepo: sn.repo,\n+\t\ttree: tree,\n+\t}, nil\n+\treturn nil, fuse.ENOENT\n+}\n+\n+// Statically ensure that *dir implement those interface\n+var _ = fs.HandleReadDirAller(&dir{})\n+var _ = fs.NodeStringLookuper(&dir{})\n+\n+type dir struct {\n+\trepo  *repository.Repository\n+\ttree  *restic.Tree\n+\tinode uint64\n+}\n+\n+func (d *dir) Attr(ctx context.Context, a *fuse.Attr) error {\n+\ta.Inode = d.inode\n+\ta.Mode = os.ModeDir | 0555\n+\treturn nil\n+}\n+\n+func (d *dir) ReadDirAll(ctx context.Context) ([]fuse.Dirent, error) {\n+\tret := make([]fuse.Dirent, 0, len(d.tree.Nodes))\n+\n+\tfor _, node := range d.tree.Nodes {\n+\t\tvar typ fuse.DirentType\n+\t\tswitch {\n+\t\tcase node.Mode.IsDir():\n+\t\t\ttyp = fuse.DT_Dir\n+\t\tcase node.Mode.IsRegular():\n+\t\t\ttyp = fuse.DT_File\n+\t\t}\n+\n+\t\tret = append(ret, fuse.Dirent{\n+\t\t\tInode: node.Inode,\n+\t\t\tType:  typ,\n+\t\t\tName:  node.Name,\n+\t\t})\n+\t}\n+\n+\treturn ret, nil\n+}\n+\n+func (d *dir) Lookup(ctx context.Context, name string) (fs.Node, error) {\n+\tfor _, node := range d.tree.Nodes {\n+\t\tif node.Name == name {\n+\t\t\tswitch {\n+\t\t\tcase node.Mode.IsDir():\n+\t\t\t\tsubtree, err := restic.LoadTree(d.repo, node.Subtree)\n+\t\t\t\tif err != nil {\n+\t\t\t\t\treturn nil, err\n+\t\t\t\t}\n+\t\t\t\treturn &dir{\n+\t\t\t\t\trepo:  d.repo,\n+\t\t\t\t\ttree:  subtree,\n+\t\t\t\t\tinode: binary.BigEndian.Uint64(node.Subtree[:8]),\n+\t\t\t\t}, nil\n+\t\t\tcase node.Mode.IsRegular():\n+\t\t\t\treturn makeFile(d.repo, node)\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\treturn nil, fuse.ENOENT\n+}\n+\n+// Statically ensure that *file implements the given interface\n+var _ = fs.HandleReader(&file{})\n+\n+type file struct {\n+\trepo *repository.Repository\n+\tnode *restic.Node\n+\n+\tsizes []uint32\n+\n+\t// cleartext contents\n+\tclearContent [][]byte\n+}\n+\n+func makeFile(repo *repository.Repository, node *restic.Node) (*file, error) {\n+\tsizes := make([]uint32, len(node.Content))\n+\tfor i, bid := range node.Content {\n+\t\t_, _, _, length, err := repo.Index().Lookup(bid)\n+\t\tif err != nil {\n+\t\t\treturn nil, err\n+\t\t}\n+\t\tsizes[i] = uint32(length) - crypto.Extension\n+\t}\n+\n+\treturn &file{\n+\t\trepo:         repo,\n+\t\tnode:         node,\n+\t\tsizes:        sizes,\n+\t\tclearContent: make([][]byte, len(node.Content)),\n+\t}, nil\n+}\n+\n+func (f *file) Attr(ctx context.Context, a *fuse.Attr) error {\n+\ta.Inode = f.node.Inode\n+\ta.Mode = f.node.Mode\n+\ta.Size = f.node.Size\n+\treturn nil\n+}\n+\n+func (f *file) Read(ctx context.Context, req *fuse.ReadRequest, resp *fuse.ReadResponse) error {","path":"cmd/restic/cmd_mount.go","position":262,"original_position":262,"commit_id":"166926f450d04914dfafe9d9ce6f5481c528e4f8","original_commit_id":"1fd405bc12304c5d69157aea1e6207f3ab43c4c4","user":{"login":"fw42","id":2072686,"avatar_url":"https://avatars.githubusercontent.com/u/2072686?v=3","gravatar_id":"","url":"https://api.github.com/users/fw42","html_url":"https://github.com/fw42","followers_url":"https://api.github.com/users/fw42/followers","following_url":"https://api.github.com/users/fw42/following{/other_user}","gists_url":"https://api.github.com/users/fw42/gists{/gist_id}","starred_url":"https://api.github.com/users/fw42/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fw42/subscriptions","organizations_url":"https://api.github.com/users/fw42/orgs","repos_url":"https://api.github.com/users/fw42/repos","events_url":"https://api.github.com/users/fw42/events{/privacy}","received_events_url":"https://api.github.com/users/fw42/received_events","type":"User","site_admin":false},"body":"I find this method hard to understand... is there any way we could make it easier? maybe by breaking it down into smaller ones with descriptive names?","created_at":"2015-07-18T23:28:37Z","updated_at":"2015-07-18T23:28:37Z","html_url":"https://github.com/restic/restic/pull/122#discussion_r34952775","pull_request_url":"https://api.github.com/repos/restic/restic/pulls/122","_links":{"self":{"href":"https://api.github.com/repos/restic/restic/pulls/comments/34952775"},"html":{"href":"https://github.com/restic/restic/pull/122#discussion_r34952775"},"pull_request":{"href":"https://api.github.com/repos/restic/restic/pulls/122"}}},"pull_request":{"url":"https://api.github.com/repos/restic/restic/pulls/122","id":32802408,"html_url":"https://github.com/restic/restic/pull/122","diff_url":"https://github.com/restic/restic/pull/122.diff","patch_url":"https://github.com/restic/restic/pull/122.patch","issue_url":"https://api.github.com/repos/restic/restic/issues/122","number":122,"state":"open","locked":false,"title":"Add simple mount command","user":{"login":"rakoo","id":501707,"avatar_url":"https://avatars.githubusercontent.com/u/501707?v=3","gravatar_id":"","url":"https://api.github.com/users/rakoo","html_url":"https://github.com/rakoo","followers_url":"https://api.github.com/users/rakoo/followers","following_url":"https://api.github.com/users/rakoo/following{/other_user}","gists_url":"https://api.github.com/users/rakoo/gists{/gist_id}","starred_url":"https://api.github.com/users/rakoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rakoo/subscriptions","organizations_url":"https://api.github.com/users/rakoo/orgs","repos_url":"https://api.github.com/users/rakoo/repos","events_url":"https://api.github.com/users/rakoo/events{/privacy}","received_events_url":"https://api.github.com/users/rakoo/received_events","type":"User","site_admin":false},"body":"For consideration only; I don't expect this to be merged as-is.\r\n\r\nHere's a very simple `mount` command to mount a restic repo on some mountpoint through fuse.\r\n\r\nTo use, do this:\r\n\r\n```shell\r\n$ mkdir /some/mount/path\r\n$ make\r\n$ ./restic -r /path/to/repo mount /some/mount/path\r\n(do your stuff in /some/mount/path: cat, mplayer, thunar, whatever)\r\n(stop the mount with ^C)\r\n$ sudo fusermount -u /some/moutn/path # this step is important, I don't know the gritty details of fuse/filesystems so I couldn't explain why\r\n```\r\n\r\nSome notes about how it works:\r\n\r\n- Everything is read-only (dirs are executable to be browseable)\r\n- It seems to work ok for most files...\r\n- ...except for videos, it is extremely laggy. A quick look at `iotop` shows almost no disk usage; further profiling is needed\r\n- I think using `mount` as a command name makes more sense than using `fuse`, because it is the actual thing the user wants to do whereas `fuse` is just the implementation.\r\n\r\nHere's the hierarchy (inspired by bup):\r\n\r\n```\r\nmountpath\r\n  `- snapshots (a pseudo dir)\r\n        |- <snapshot date1> (another pseudo dir)\r\n        |- <snapshot date2>\r\n        | # there will be a \"latest\" symlink here that points to the latest snapshot directly\r\n        `- <snapshot date3>\r\n               `- <snapshot top dir, such as /home/rakoo/Documents>\r\n                       |- dir1 (here we start real dirs)\r\n                       |   |- dir 11\r\n                       |   |    `- file 111\r\n                       |   `- file 12\r\n                       `- dir2\r\n```\r\n\r\nCloses #27 ","created_at":"2015-04-07T20:31:35Z","updated_at":"2015-07-18T23:28:37Z","closed_at":null,"merged_at":null,"merge_commit_sha":"95d1b14c2a95d5a037fe9555c8dc702db4f09c62","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/restic/restic/pulls/122/commits","review_comments_url":"https://api.github.com/repos/restic/restic/pulls/122/comments","review_comment_url":"https://api.github.com/repos/restic/restic/pulls/comments{/number}","comments_url":"https://api.github.com/repos/restic/restic/issues/122/comments","statuses_url":"https://api.github.com/repos/restic/restic/statuses/166926f450d04914dfafe9d9ce6f5481c528e4f8","head":{"label":"rakoo:fuse","ref":"fuse","sha":"166926f450d04914dfafe9d9ce6f5481c528e4f8","user":{"login":"rakoo","id":501707,"avatar_url":"https://avatars.githubusercontent.com/u/501707?v=3","gravatar_id":"","url":"https://api.github.com/users/rakoo","html_url":"https://github.com/rakoo","followers_url":"https://api.github.com/users/rakoo/followers","following_url":"https://api.github.com/users/rakoo/following{/other_user}","gists_url":"https://api.github.com/users/rakoo/gists{/gist_id}","starred_url":"https://api.github.com/users/rakoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rakoo/subscriptions","organizations_url":"https://api.github.com/users/rakoo/orgs","repos_url":"https://api.github.com/users/rakoo/repos","events_url":"https://api.github.com/users/rakoo/events{/privacy}","received_events_url":"https://api.github.com/users/rakoo/received_events","type":"User","site_admin":false},"repo":{"id":33403572,"name":"restic","full_name":"rakoo/restic","owner":{"login":"rakoo","id":501707,"avatar_url":"https://avatars.githubusercontent.com/u/501707?v=3","gravatar_id":"","url":"https://api.github.com/users/rakoo","html_url":"https://github.com/rakoo","followers_url":"https://api.github.com/users/rakoo/followers","following_url":"https://api.github.com/users/rakoo/following{/other_user}","gists_url":"https://api.github.com/users/rakoo/gists{/gist_id}","starred_url":"https://api.github.com/users/rakoo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rakoo/subscriptions","organizations_url":"https://api.github.com/users/rakoo/orgs","repos_url":"https://api.github.com/users/rakoo/repos","events_url":"https://api.github.com/users/rakoo/events{/privacy}","received_events_url":"https://api.github.com/users/rakoo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/rakoo/restic","description":"restic backup program","fork":true,"url":"https://api.github.com/repos/rakoo/restic","forks_url":"https://api.github.com/repos/rakoo/restic/forks","keys_url":"https://api.github.com/repos/rakoo/restic/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rakoo/restic/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rakoo/restic/teams","hooks_url":"https://api.github.com/repos/rakoo/restic/hooks","issue_events_url":"https://api.github.com/repos/rakoo/restic/issues/events{/number}","events_url":"https://api.github.com/repos/rakoo/restic/events","assignees_url":"https://api.github.com/repos/rakoo/restic/assignees{/user}","branches_url":"https://api.github.com/repos/rakoo/restic/branches{/branch}","tags_url":"https://api.github.com/repos/rakoo/restic/tags","blobs_url":"https://api.github.com/repos/rakoo/restic/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rakoo/restic/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rakoo/restic/git/refs{/sha}","trees_url":"https://api.github.com/repos/rakoo/restic/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rakoo/restic/statuses/{sha}","languages_url":"https://api.github.com/repos/rakoo/restic/languages","stargazers_url":"https://api.github.com/repos/rakoo/restic/stargazers","contributors_url":"https://api.github.com/repos/rakoo/restic/contributors","subscribers_url":"https://api.github.com/repos/rakoo/restic/subscribers","subscription_url":"https://api.github.com/repos/rakoo/restic/subscription","commits_url":"https://api.github.com/repos/rakoo/restic/commits{/sha}","git_commits_url":"https://api.github.com/repos/rakoo/restic/git/commits{/sha}","comments_url":"https://api.github.com/repos/rakoo/restic/comments{/number}","issue_comment_url":"https://api.github.com/repos/rakoo/restic/issues/comments{/number}","contents_url":"https://api.github.com/repos/rakoo/restic/contents/{+path}","compare_url":"https://api.github.com/repos/rakoo/restic/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rakoo/restic/merges","archive_url":"https://api.github.com/repos/rakoo/restic/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rakoo/restic/downloads","issues_url":"https://api.github.com/repos/rakoo/restic/issues{/number}","pulls_url":"https://api.github.com/repos/rakoo/restic/pulls{/number}","milestones_url":"https://api.github.com/repos/rakoo/restic/milestones{/number}","notifications_url":"https://api.github.com/repos/rakoo/restic/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rakoo/restic/labels{/name}","releases_url":"https://api.github.com/repos/rakoo/restic/releases{/id}","created_at":"2015-04-04T11:39:12Z","updated_at":"2015-04-04T11:52:10Z","pushed_at":"2015-07-18T23:09:52Z","git_url":"git://github.com/rakoo/restic.git","ssh_url":"git@github.com:rakoo/restic.git","clone_url":"https://github.com/rakoo/restic.git","svn_url":"https://github.com/rakoo/restic","homepage":"","size":9355,"stargazers_count":0,"watchers_count":0,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"restic:master","ref":"master","sha":"b6b1f41f2e1fd25e7899bbb32c5f7b357bd3e2b9","user":{"login":"restic","id":10073512,"avatar_url":"https://avatars.githubusercontent.com/u/10073512?v=3","gravatar_id":"","url":"https://api.github.com/users/restic","html_url":"https://github.com/restic","followers_url":"https://api.github.com/users/restic/followers","following_url":"https://api.github.com/users/restic/following{/other_user}","gists_url":"https://api.github.com/users/restic/gists{/gist_id}","starred_url":"https://api.github.com/users/restic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/restic/subscriptions","organizations_url":"https://api.github.com/users/restic/orgs","repos_url":"https://api.github.com/users/restic/repos","events_url":"https://api.github.com/users/restic/events{/privacy}","received_events_url":"https://api.github.com/users/restic/received_events","type":"Organization","site_admin":false},"repo":{"id":19205896,"name":"restic","full_name":"restic/restic","owner":{"login":"restic","id":10073512,"avatar_url":"https://avatars.githubusercontent.com/u/10073512?v=3","gravatar_id":"","url":"https://api.github.com/users/restic","html_url":"https://github.com/restic","followers_url":"https://api.github.com/users/restic/followers","following_url":"https://api.github.com/users/restic/following{/other_user}","gists_url":"https://api.github.com/users/restic/gists{/gist_id}","starred_url":"https://api.github.com/users/restic/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/restic/subscriptions","organizations_url":"https://api.github.com/users/restic/orgs","repos_url":"https://api.github.com/users/restic/repos","events_url":"https://api.github.com/users/restic/events{/privacy}","received_events_url":"https://api.github.com/users/restic/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/restic/restic","description":"restic backup program","fork":false,"url":"https://api.github.com/repos/restic/restic","forks_url":"https://api.github.com/repos/restic/restic/forks","keys_url":"https://api.github.com/repos/restic/restic/keys{/key_id}","collaborators_url":"https://api.github.com/repos/restic/restic/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/restic/restic/teams","hooks_url":"https://api.github.com/repos/restic/restic/hooks","issue_events_url":"https://api.github.com/repos/restic/restic/issues/events{/number}","events_url":"https://api.github.com/repos/restic/restic/events","assignees_url":"https://api.github.com/repos/restic/restic/assignees{/user}","branches_url":"https://api.github.com/repos/restic/restic/branches{/branch}","tags_url":"https://api.github.com/repos/restic/restic/tags","blobs_url":"https://api.github.com/repos/restic/restic/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/restic/restic/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/restic/restic/git/refs{/sha}","trees_url":"https://api.github.com/repos/restic/restic/git/trees{/sha}","statuses_url":"https://api.github.com/repos/restic/restic/statuses/{sha}","languages_url":"https://api.github.com/repos/restic/restic/languages","stargazers_url":"https://api.github.com/repos/restic/restic/stargazers","contributors_url":"https://api.github.com/repos/restic/restic/contributors","subscribers_url":"https://api.github.com/repos/restic/restic/subscribers","subscription_url":"https://api.github.com/repos/restic/restic/subscription","commits_url":"https://api.github.com/repos/restic/restic/commits{/sha}","git_commits_url":"https://api.github.com/repos/restic/restic/git/commits{/sha}","comments_url":"https://api.github.com/repos/restic/restic/comments{/number}","issue_comment_url":"https://api.github.com/repos/restic/restic/issues/comments{/number}","contents_url":"https://api.github.com/repos/restic/restic/contents/{+path}","compare_url":"https://api.github.com/repos/restic/restic/compare/{base}...{head}","merges_url":"https://api.github.com/repos/restic/restic/merges","archive_url":"https://api.github.com/repos/restic/restic/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/restic/restic/downloads","issues_url":"https://api.github.com/repos/restic/restic/issues{/number}","pulls_url":"https://api.github.com/repos/restic/restic/pulls{/number}","milestones_url":"https://api.github.com/repos/restic/restic/milestones{/number}","notifications_url":"https://api.github.com/repos/restic/restic/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/restic/restic/labels{/name}","releases_url":"https://api.github.com/repos/restic/restic/releases{/id}","created_at":"2014-04-27T14:07:58Z","updated_at":"2015-07-14T15:31:28Z","pushed_at":"2015-07-18T23:09:53Z","git_url":"git://github.com/restic/restic.git","ssh_url":"git@github.com:restic/restic.git","clone_url":"https://github.com/restic/restic.git","svn_url":"https://github.com/restic/restic","homepage":"","size":11116,"stargazers_count":134,"watchers_count":134,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":15,"mirror_url":null,"open_issues_count":66,"forks":15,"open_issues":66,"watchers":134,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/restic/restic/pulls/122"},"html":{"href":"https://github.com/restic/restic/pull/122"},"issue":{"href":"https://api.github.com/repos/restic/restic/issues/122"},"comments":{"href":"https://api.github.com/repos/restic/restic/issues/122/comments"},"review_comments":{"href":"https://api.github.com/repos/restic/restic/pulls/122/comments"},"review_comment":{"href":"https://api.github.com/repos/restic/restic/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/restic/restic/pulls/122/commits"},"statuses":{"href":"https://api.github.com/repos/restic/restic/statuses/166926f450d04914dfafe9d9ce6f5481c528e4f8"}}}}