{"action":"created","comment":{"url":"https://api.github.com/repos/snapcore/snapd/pulls/comments/74219571","id":74219571,"diff_hunk":"@@ -0,0 +1,386 @@\n+// -*- Mode: Go; indent-tabs-mode: t -*-\n+\n+/*\n+ * Copyright (C) 2014-2016 Canonical Ltd\n+ *\n+ * This program is free software: you can redistribute it and/or modify\n+ * it under the terms of the GNU General Public License version 3 as\n+ * published by the Free Software Foundation.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.\n+ *\n+ */\n+\n+package image\n+\n+import (\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"io/ioutil\"\n+\t\"os\"\n+\t\"os/exec\"\n+\t\"path/filepath\"\n+\n+\t\"github.com/snapcore/snapd/arch\"\n+\t\"github.com/snapcore/snapd/asserts\"\n+\t\"github.com/snapcore/snapd/boot\"\n+\t\"github.com/snapcore/snapd/dirs\"\n+\t\"github.com/snapcore/snapd/osutil\"\n+\t\"github.com/snapcore/snapd/overlord/auth\"\n+\t\"github.com/snapcore/snapd/partition\"\n+\t\"github.com/snapcore/snapd/progress\"\n+\t\"github.com/snapcore/snapd/release\"\n+\t\"github.com/snapcore/snapd/snap\"\n+\t\"github.com/snapcore/snapd/snap/squashfs\"\n+\t\"github.com/snapcore/snapd/store\"\n+)\n+\n+type Options struct {\n+\tSnaps            []string\n+\tRootdir          string\n+\tChannel          string\n+\tModelAssertionFn string\n+\tGadgetUnpackDir  string\n+}\n+\n+func Prepare(opts *Options) error {\n+\tif err := downloadUnpackGadget(opts); err != nil {\n+\t\treturn err\n+\t}\n+\n+\treturn bootstrapToRootdir(opts)\n+}\n+\n+func decodeModelAssertion(fn string) (*asserts.Model, error) {\n+\trawAssert, err := ioutil.ReadFile(fn)\n+\tif err != nil {\n+\t\treturn nil, fmt.Errorf(\"cannot read model assertion: %s\", err)\n+\t}\n+\n+\tass, err := asserts.Decode(rawAssert)\n+\tif err != nil {\n+\t\treturn nil, fmt.Errorf(\"cannot decode model assertion %q: %s\", fn, err)\n+\t}\n+\treturn ass.(*asserts.Model), nil\n+}\n+\n+func downloadUnpackGadget(opts *Options) error {\n+\tmodel, err := decodeModelAssertion(opts.ModelAssertionFn)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tif err := os.MkdirAll(opts.GadgetUnpackDir, 0755); err != nil {\n+\t\treturn fmt.Errorf(\"cannot create gadget unpack dir %q: %s\", opts.GadgetUnpackDir, err)\n+\t}\n+\n+\tdlOpts := &downloadOptions{\n+\t\tTargetDir:    opts.GadgetUnpackDir,\n+\t\tChannel:      opts.Channel,\n+\t\tStoreID:      model.Store(),\n+\t\tArchitecture: model.Architecture(),\n+\t}\n+\tsnapFn, _, err := acquireSnap(model.Gadget(), dlOpts)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\t// FIXME: jumping through layers here, we need to make\n+\t//        unpack part of the container interface (again)\n+\tsnap := squashfs.New(snapFn)\n+\treturn snap.Unpack(\"*\", opts.GadgetUnpackDir)\n+}\n+\n+func acquireSnap(snapName string, dlOpts *downloadOptions) (string, *snap.Info, error) {\n+\tif osutil.FileExists(snapName) {\n+\t\treturn copyLocalSnapFile(snapName, dlOpts.TargetDir)\n+\t}\n+\n+\treturn downloadSnapWithSideInfo(snapName, dlOpts)\n+}\n+\n+func bootstrapToRootdir(opts *Options) error {\n+\tif opts.Rootdir != \"\" {\n+\t\tdirs.SetRootDir(opts.Rootdir)\n+\t\tdefer dirs.SetRootDir(\"/\")\n+\t}\n+\n+\t// sanity check target\n+\tif osutil.FileExists(dirs.SnapStateFile) {\n+\t\treturn fmt.Errorf(\"cannot bootstrap over existing system\")\n+\t}\n+\n+\tmodel, err := decodeModelAssertion(opts.ModelAssertionFn)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\t// put snaps in place\n+\tif err := os.MkdirAll(dirs.SnapBlobDir, 0755); err != nil {\n+\t\treturn err\n+\t}\n+\n+\tsnapSeedDir := filepath.Join(dirs.SnapSeedDir, \"snaps\")\n+\tdlOpts := &downloadOptions{\n+\t\tTargetDir:    snapSeedDir,\n+\t\tChannel:      opts.Channel,\n+\t\tStoreID:      model.Store(),\n+\t\tArchitecture: model.Architecture(),\n+\t}\n+\n+\t// FIXME: support sideloading snaps by copying the boostrap.snaps\n+\t//        first and keeping track of the already downloaded names\n+\tsnaps := []string{}\n+\tsnaps = append(snaps, opts.Snaps...)\n+\tsnaps = append(snaps, model.Gadget())\n+\tsnaps = append(snaps, model.Core())\n+\tsnaps = append(snaps, model.Kernel())\n+\tsnaps = append(snaps, model.RequiredSnaps()...)\n+\n+\tfor _, d := range []string{dirs.SnapBlobDir, snapSeedDir} {\n+\t\tif err := os.MkdirAll(d, 0755); err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t}\n+\n+\tvar seedYaml snap.Seed\n+\tfor _, snapName := range snaps {\n+\t\tfmt.Printf(\"Fetching %s\\n\", snapName)\n+\t\tfn, info, err := acquireSnap(snapName, dlOpts)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t\t// kernel/os are required for booting\n+\t\tif snapName == model.Kernel() || snapName == model.Core() {\n+\t\t\tif err := osutil.CopyFile(fn, filepath.Join(dirs.SnapBlobDir, filepath.Base(fn)), 0); err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t}\n+\t\t// set seed.yaml\n+\t\tseedYaml.Snaps = append(seedYaml.Snaps, &snap.SeedSnap{\n+\t\t\tName:        info.Name(),\n+\t\t\tSnapID:      info.SnapID,\n+\t\t\tRevision:    info.Revision,\n+\t\t\tChannel:     info.Channel,\n+\t\t\tDeveloperID: info.DeveloperID,\n+\t\t\tDeveloper:   info.Developer,\n+\t\t\tFile:        filepath.Base(fn),\n+\t\t})\n+\t}\n+\tif err := seedYaml.Write(); err != nil {\n+\t\treturn fmt.Errorf(\"cannot write seed.yaml: %s\", err)\n+\t}\n+\n+\t// now do the bootloader stuff\n+\tif err := partition.InstallBootConfig(opts.GadgetUnpackDir); err != nil {\n+\t\treturn err\n+\t}\n+\n+\tif err := setBootvars(); err != nil {\n+\t\treturn err\n+\t}\n+\n+\treturn nil\n+}\n+\n+func setBootvars() error {\n+\t// set the bootvars for kernel/os snaps so that the system\n+\t// actually boots and can do the `firstboot` import of the snaps.\n+\t//\n+\t// there is also no mounted os/kernel snap, all we have are the\n+\t// blobs\n+\n+\tbootloader, err := partition.FindBootloader()\n+\tif err != nil {\n+\t\treturn fmt.Errorf(\"can not set kernel/os bootvars: %s\", err)\n+\t}\n+\n+\tsnaps, _ := filepath.Glob(filepath.Join(dirs.SnapBlobDir, \"*.snap\"))\n+\tif len(snaps) == 0 {\n+\t\treturn fmt.Errorf(\"internal error: cannot find os/kernel snap\")\n+\t}\n+\tfor _, fullname := range snaps {\n+\t\tbootvar := \"\"\n+\n+\t\t// detect type\n+\t\tsnapFile, err := snap.Open(fullname)\n+\t\tif err != nil {\n+\t\t\treturn fmt.Errorf(\"can not read %v\", fullname)\n+\t\t}\n+\t\t// read .sideinfo\n+\t\tvar si snap.SideInfo\n+\t\tsiFn := fullname + \".sideinfo\"\n+\t\tif osutil.FileExists(siFn) {\n+\t\t\tj, err := ioutil.ReadFile(siFn)\n+\t\t\tif err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t\tif err := json.Unmarshal(j, &si); err != nil {\n+\t\t\t\treturn fmt.Errorf(\"cannot read metadata: %s %s\\n\", siFn, err)\n+\t\t\t}\n+\t\t}\n+\t\tinfo, err := snap.ReadInfoFromSnapFile(snapFile, &si)\n+\t\tif err != nil {\n+\t\t\treturn fmt.Errorf(\"can not get info for %v\", fullname)\n+\t\t}\n+\t\t// local install\n+\t\tif info.Revision.Unset() {\n+\t\t\tinfo.Revision = snap.R(-1)\n+\t\t}\n+\n+\t\tswitch info.Type {\n+\t\tcase snap.TypeOS:\n+\t\t\tbootvar = \"snap_core\"\n+\t\tcase snap.TypeKernel:\n+\t\t\tbootvar = \"snap_kernel\"\n+\t\t\tif err := extractKernelAssets(fullname, info); err != nil {\n+\t\t\t\treturn err\n+\t\t\t}\n+\t\t}\n+\n+\t\tname := filepath.Base(fullname)","path":"image/image.go","position":249,"original_position":245,"commit_id":"48075dcfa766016069d5fd8899d6b4fe04b584e2","original_commit_id":"2e355920a6de3403c04619f8e48eec8ad220516c","user":{"login":"mvo5","id":914418,"avatar_url":"https://avatars.githubusercontent.com/u/914418?v=3","gravatar_id":"","url":"https://api.github.com/users/mvo5","html_url":"https://github.com/mvo5","followers_url":"https://api.github.com/users/mvo5/followers","following_url":"https://api.github.com/users/mvo5/following{/other_user}","gists_url":"https://api.github.com/users/mvo5/gists{/gist_id}","starred_url":"https://api.github.com/users/mvo5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mvo5/subscriptions","organizations_url":"https://api.github.com/users/mvo5/orgs","repos_url":"https://api.github.com/users/mvo5/repos","events_url":"https://api.github.com/users/mvo5/events{/privacy}","received_events_url":"https://api.github.com/users/mvo5/received_events","type":"User","site_admin":false},"body":"Indeed, simpler this way. Fixed.","created_at":"2016-08-10T10:19:04Z","updated_at":"2016-08-10T10:19:04Z","html_url":"https://github.com/snapcore/snapd/pull/1548#discussion_r74219571","pull_request_url":"https://api.github.com/repos/snapcore/snapd/pulls/1548","_links":{"self":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/comments/74219571"},"html":{"href":"https://github.com/snapcore/snapd/pull/1548#discussion_r74219571"},"pull_request":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1548"}}},"pull_request":{"url":"https://api.github.com/repos/snapcore/snapd/pulls/1548","id":77480669,"html_url":"https://github.com/snapcore/snapd/pull/1548","diff_url":"https://github.com/snapcore/snapd/pull/1548.diff","patch_url":"https://github.com/snapcore/snapd/pull/1548.patch","issue_url":"https://api.github.com/repos/snapcore/snapd/issues/1548","number":1548,"state":"open","locked":false,"title":"many: add new `snap prepare-image` command for ubuntu-image","user":{"login":"mvo5","id":914418,"avatar_url":"https://avatars.githubusercontent.com/u/914418?v=3","gravatar_id":"","url":"https://api.github.com/users/mvo5","html_url":"https://github.com/mvo5","followers_url":"https://api.github.com/users/mvo5/followers","following_url":"https://api.github.com/users/mvo5/following{/other_user}","gists_url":"https://api.github.com/users/mvo5/gists{/gist_id}","starred_url":"https://api.github.com/users/mvo5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mvo5/subscriptions","organizations_url":"https://api.github.com/users/mvo5/orgs","repos_url":"https://api.github.com/users/mvo5/repos","events_url":"https://api.github.com/users/mvo5/events{/privacy}","received_events_url":"https://api.github.com/users/mvo5/received_events","type":"User","site_admin":false},"body":"A new branch to unblock `ubuntu-image`. This implements the snapd side of image creation, namely fetching snaps, dealing with the kernel and setting the boot-varialbes and boot configuration (but not bootloader installation).","created_at":"2016-07-14T15:55:38Z","updated_at":"2016-08-10T10:19:04Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bf1455644fc7453e8389dd6a41f9975825a8d92f","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/snapcore/snapd/pulls/1548/commits","review_comments_url":"https://api.github.com/repos/snapcore/snapd/pulls/1548/comments","review_comment_url":"https://api.github.com/repos/snapcore/snapd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/snapcore/snapd/issues/1548/comments","statuses_url":"https://api.github.com/repos/snapcore/snapd/statuses/48075dcfa766016069d5fd8899d6b4fe04b584e2","head":{"label":"mvo5:feature/snap-bootstrap","ref":"feature/snap-bootstrap","sha":"48075dcfa766016069d5fd8899d6b4fe04b584e2","user":{"login":"mvo5","id":914418,"avatar_url":"https://avatars.githubusercontent.com/u/914418?v=3","gravatar_id":"","url":"https://api.github.com/users/mvo5","html_url":"https://github.com/mvo5","followers_url":"https://api.github.com/users/mvo5/followers","following_url":"https://api.github.com/users/mvo5/following{/other_user}","gists_url":"https://api.github.com/users/mvo5/gists{/gist_id}","starred_url":"https://api.github.com/users/mvo5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mvo5/subscriptions","organizations_url":"https://api.github.com/users/mvo5/orgs","repos_url":"https://api.github.com/users/mvo5/repos","events_url":"https://api.github.com/users/mvo5/events{/privacy}","received_events_url":"https://api.github.com/users/mvo5/received_events","type":"User","site_admin":false},"repo":{"id":45067233,"name":"snappy","full_name":"mvo5/snappy","owner":{"login":"mvo5","id":914418,"avatar_url":"https://avatars.githubusercontent.com/u/914418?v=3","gravatar_id":"","url":"https://api.github.com/users/mvo5","html_url":"https://github.com/mvo5","followers_url":"https://api.github.com/users/mvo5/followers","following_url":"https://api.github.com/users/mvo5/following{/other_user}","gists_url":"https://api.github.com/users/mvo5/gists{/gist_id}","starred_url":"https://api.github.com/users/mvo5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mvo5/subscriptions","organizations_url":"https://api.github.com/users/mvo5/orgs","repos_url":"https://api.github.com/users/mvo5/repos","events_url":"https://api.github.com/users/mvo5/events{/privacy}","received_events_url":"https://api.github.com/users/mvo5/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/mvo5/snappy","description":"Snappy is the software at the heart of Ubuntu Core.","fork":true,"url":"https://api.github.com/repos/mvo5/snappy","forks_url":"https://api.github.com/repos/mvo5/snappy/forks","keys_url":"https://api.github.com/repos/mvo5/snappy/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mvo5/snappy/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mvo5/snappy/teams","hooks_url":"https://api.github.com/repos/mvo5/snappy/hooks","issue_events_url":"https://api.github.com/repos/mvo5/snappy/issues/events{/number}","events_url":"https://api.github.com/repos/mvo5/snappy/events","assignees_url":"https://api.github.com/repos/mvo5/snappy/assignees{/user}","branches_url":"https://api.github.com/repos/mvo5/snappy/branches{/branch}","tags_url":"https://api.github.com/repos/mvo5/snappy/tags","blobs_url":"https://api.github.com/repos/mvo5/snappy/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mvo5/snappy/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mvo5/snappy/git/refs{/sha}","trees_url":"https://api.github.com/repos/mvo5/snappy/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mvo5/snappy/statuses/{sha}","languages_url":"https://api.github.com/repos/mvo5/snappy/languages","stargazers_url":"https://api.github.com/repos/mvo5/snappy/stargazers","contributors_url":"https://api.github.com/repos/mvo5/snappy/contributors","subscribers_url":"https://api.github.com/repos/mvo5/snappy/subscribers","subscription_url":"https://api.github.com/repos/mvo5/snappy/subscription","commits_url":"https://api.github.com/repos/mvo5/snappy/commits{/sha}","git_commits_url":"https://api.github.com/repos/mvo5/snappy/git/commits{/sha}","comments_url":"https://api.github.com/repos/mvo5/snappy/comments{/number}","issue_comment_url":"https://api.github.com/repos/mvo5/snappy/issues/comments{/number}","contents_url":"https://api.github.com/repos/mvo5/snappy/contents/{+path}","compare_url":"https://api.github.com/repos/mvo5/snappy/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mvo5/snappy/merges","archive_url":"https://api.github.com/repos/mvo5/snappy/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mvo5/snappy/downloads","issues_url":"https://api.github.com/repos/mvo5/snappy/issues{/number}","pulls_url":"https://api.github.com/repos/mvo5/snappy/pulls{/number}","milestones_url":"https://api.github.com/repos/mvo5/snappy/milestones{/number}","notifications_url":"https://api.github.com/repos/mvo5/snappy/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mvo5/snappy/labels{/name}","releases_url":"https://api.github.com/repos/mvo5/snappy/releases{/id}","deployments_url":"https://api.github.com/repos/mvo5/snappy/deployments","created_at":"2015-10-27T20:12:18Z","updated_at":"2016-01-11T10:04:34Z","pushed_at":"2016-08-10T09:30:17Z","git_url":"git://github.com/mvo5/snappy.git","ssh_url":"git@github.com:mvo5/snappy.git","clone_url":"https://github.com/mvo5/snappy.git","svn_url":"https://github.com/mvo5/snappy","homepage":null,"size":34404,"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":"snapcore:master","ref":"master","sha":"325358a0295b2e898345ca99645870b78c0d5fe9","user":{"login":"snapcore","id":19532717,"avatar_url":"https://avatars.githubusercontent.com/u/19532717?v=3","gravatar_id":"","url":"https://api.github.com/users/snapcore","html_url":"https://github.com/snapcore","followers_url":"https://api.github.com/users/snapcore/followers","following_url":"https://api.github.com/users/snapcore/following{/other_user}","gists_url":"https://api.github.com/users/snapcore/gists{/gist_id}","starred_url":"https://api.github.com/users/snapcore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snapcore/subscriptions","organizations_url":"https://api.github.com/users/snapcore/orgs","repos_url":"https://api.github.com/users/snapcore/repos","events_url":"https://api.github.com/users/snapcore/events{/privacy}","received_events_url":"https://api.github.com/users/snapcore/received_events","type":"Organization","site_admin":false},"repo":{"id":44672744,"name":"snapd","full_name":"snapcore/snapd","owner":{"login":"snapcore","id":19532717,"avatar_url":"https://avatars.githubusercontent.com/u/19532717?v=3","gravatar_id":"","url":"https://api.github.com/users/snapcore","html_url":"https://github.com/snapcore","followers_url":"https://api.github.com/users/snapcore/followers","following_url":"https://api.github.com/users/snapcore/following{/other_user}","gists_url":"https://api.github.com/users/snapcore/gists{/gist_id}","starred_url":"https://api.github.com/users/snapcore/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/snapcore/subscriptions","organizations_url":"https://api.github.com/users/snapcore/orgs","repos_url":"https://api.github.com/users/snapcore/repos","events_url":"https://api.github.com/users/snapcore/events{/privacy}","received_events_url":"https://api.github.com/users/snapcore/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/snapcore/snapd","description":"The snapd and snap tools enable systems to work with .snap files.","fork":false,"url":"https://api.github.com/repos/snapcore/snapd","forks_url":"https://api.github.com/repos/snapcore/snapd/forks","keys_url":"https://api.github.com/repos/snapcore/snapd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/snapcore/snapd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/snapcore/snapd/teams","hooks_url":"https://api.github.com/repos/snapcore/snapd/hooks","issue_events_url":"https://api.github.com/repos/snapcore/snapd/issues/events{/number}","events_url":"https://api.github.com/repos/snapcore/snapd/events","assignees_url":"https://api.github.com/repos/snapcore/snapd/assignees{/user}","branches_url":"https://api.github.com/repos/snapcore/snapd/branches{/branch}","tags_url":"https://api.github.com/repos/snapcore/snapd/tags","blobs_url":"https://api.github.com/repos/snapcore/snapd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/snapcore/snapd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/snapcore/snapd/git/refs{/sha}","trees_url":"https://api.github.com/repos/snapcore/snapd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/snapcore/snapd/statuses/{sha}","languages_url":"https://api.github.com/repos/snapcore/snapd/languages","stargazers_url":"https://api.github.com/repos/snapcore/snapd/stargazers","contributors_url":"https://api.github.com/repos/snapcore/snapd/contributors","subscribers_url":"https://api.github.com/repos/snapcore/snapd/subscribers","subscription_url":"https://api.github.com/repos/snapcore/snapd/subscription","commits_url":"https://api.github.com/repos/snapcore/snapd/commits{/sha}","git_commits_url":"https://api.github.com/repos/snapcore/snapd/git/commits{/sha}","comments_url":"https://api.github.com/repos/snapcore/snapd/comments{/number}","issue_comment_url":"https://api.github.com/repos/snapcore/snapd/issues/comments{/number}","contents_url":"https://api.github.com/repos/snapcore/snapd/contents/{+path}","compare_url":"https://api.github.com/repos/snapcore/snapd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/snapcore/snapd/merges","archive_url":"https://api.github.com/repos/snapcore/snapd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/snapcore/snapd/downloads","issues_url":"https://api.github.com/repos/snapcore/snapd/issues{/number}","pulls_url":"https://api.github.com/repos/snapcore/snapd/pulls{/number}","milestones_url":"https://api.github.com/repos/snapcore/snapd/milestones{/number}","notifications_url":"https://api.github.com/repos/snapcore/snapd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/snapcore/snapd/labels{/name}","releases_url":"https://api.github.com/repos/snapcore/snapd/releases{/id}","deployments_url":"https://api.github.com/repos/snapcore/snapd/deployments","created_at":"2015-10-21T11:51:46Z","updated_at":"2016-08-09T00:32:37Z","pushed_at":"2016-08-10T10:18:01Z","git_url":"git://github.com/snapcore/snapd.git","ssh_url":"git@github.com:snapcore/snapd.git","clone_url":"https://github.com/snapcore/snapd.git","svn_url":"https://github.com/snapcore/snapd","homepage":"","size":35377,"stargazers_count":373,"watchers_count":373,"language":"Go","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":87,"mirror_url":null,"open_issues_count":33,"forks":87,"open_issues":33,"watchers":373,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1548"},"html":{"href":"https://github.com/snapcore/snapd/pull/1548"},"issue":{"href":"https://api.github.com/repos/snapcore/snapd/issues/1548"},"comments":{"href":"https://api.github.com/repos/snapcore/snapd/issues/1548/comments"},"review_comments":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1548/comments"},"review_comment":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/snapcore/snapd/pulls/1548/commits"},"statuses":{"href":"https://api.github.com/repos/snapcore/snapd/statuses/48075dcfa766016069d5fd8899d6b4fe04b584e2"}}}}
{"actor":{"display_login":"mvo5"}}