{"action":"created","comment":{"url":"https://api.github.com/repos/Homebrew/homebrew/pulls/comments/36400904","id":36400904,"diff_hunk":"@@ -115,6 +163,12 @@ def load_tap_migrations\n   rescue LoadError\n     false\n   end\n+\n+  def load_formula_renames\n+    load 'formula_renames.rb'","path":"Library/Homebrew/cmd/update.rb","position":74,"original_position":74,"commit_id":"6acefe8885a8129375d7986a43f359f2e15a4854","original_commit_id":"c5323faaf0ba2519889ebf516c669befb8ab0c61","user":{"login":"mikemcquaid","id":125011,"avatar_url":"https://avatars.githubusercontent.com/u/125011?v=3","gravatar_id":"","url":"https://api.github.com/users/mikemcquaid","html_url":"https://github.com/mikemcquaid","followers_url":"https://api.github.com/users/mikemcquaid/followers","following_url":"https://api.github.com/users/mikemcquaid/following{/other_user}","gists_url":"https://api.github.com/users/mikemcquaid/gists{/gist_id}","starred_url":"https://api.github.com/users/mikemcquaid/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mikemcquaid/subscriptions","organizations_url":"https://api.github.com/users/mikemcquaid/orgs","repos_url":"https://api.github.com/users/mikemcquaid/repos","events_url":"https://api.github.com/users/mikemcquaid/events{/privacy}","received_events_url":"https://api.github.com/users/mikemcquaid/received_events","type":"User","site_admin":true},"body":"@xu-cheng Is that :ok:?","created_at":"2015-08-06T10:33:22Z","updated_at":"2015-08-06T10:33:22Z","html_url":"https://github.com/Homebrew/homebrew/pull/41006#discussion_r36400904","pull_request_url":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006","_links":{"self":{"href":"https://api.github.com/repos/Homebrew/homebrew/pulls/comments/36400904"},"html":{"href":"https://github.com/Homebrew/homebrew/pull/41006#discussion_r36400904"},"pull_request":{"href":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006"}}},"pull_request":{"url":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006","id":38350491,"html_url":"https://github.com/Homebrew/homebrew/pull/41006","diff_url":"https://github.com/Homebrew/homebrew/pull/41006.diff","patch_url":"https://github.com/Homebrew/homebrew/pull/41006.patch","issue_url":"https://api.github.com/repos/Homebrew/homebrew/issues/41006","number":41006,"state":"open","locked":false,"title":"GitHub Summer of Code: Formula renames","user":{"login":"vladshablinsky","id":4408920,"avatar_url":"https://avatars.githubusercontent.com/u/4408920?v=3","gravatar_id":"","url":"https://api.github.com/users/vladshablinsky","html_url":"https://github.com/vladshablinsky","followers_url":"https://api.github.com/users/vladshablinsky/followers","following_url":"https://api.github.com/users/vladshablinsky/following{/other_user}","gists_url":"https://api.github.com/users/vladshablinsky/gists{/gist_id}","starred_url":"https://api.github.com/users/vladshablinsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vladshablinsky/subscriptions","organizations_url":"https://api.github.com/users/vladshablinsky/orgs","repos_url":"https://api.github.com/users/vladshablinsky/repos","events_url":"https://api.github.com/users/vladshablinsky/events{/privacy}","received_events_url":"https://api.github.com/users/vladshablinsky/received_events","type":"User","site_admin":false},"body":"Hi! I'm a summer of code student working on \"Handling formula renames\" project https://github.com/Homebrew/homebrew/issues/14374. My mentor is @mikemcquaid. \r\n\r\nThe problem with formula renames is that if we just rename the formula and its class, user who has this formula installed will never be able to upgrade it. The second problem are dependencies, if we rename formula we won't be able to install any formula that depends on old name.\r\n\r\nThe solution is to inform user about renames and perform some migrations that won't break anything. After that user can use his software, but the software will move to new directory and the formula for the software will be changed to new name.\r\n\r\nLet's define `oldname` as an old name of the package and the formula and `newname` for new ones.\r\n\r\nApproach\r\n=======\r\nThe approach is to have `FORMULA_RENAMES` hash, that stores old names as keys and new names as values. The migrations are performed during the `update`, when we have information about added and deleted formulae from diff.\r\n\r\nThe approach doesn't allow us to create `oldname` formula after it gets renamed to `newname`.\r\n\r\nPros of this:\r\n\r\n* No mess in versions\r\n* Simple structure of metadata\r\n* Issues like https://github.com/Homebrew/homebrew/issues/15776 can still be fixed.\r\n\r\nUpdate\r\n======\r\n* Get the `formula_renames.rb` containing `FORMULA_RENAMES` from the last revision and load it.\r\n* If we find from the `report` that the core formula was deleted and we have it in the Cellar, we try to find it in `FORMULA_RENAMES` and perform migrations using `Migrator` class, described below.\r\n\r\nMigrator\r\n=======\r\n`Migrator` is a class for performing migrations for the formulae, that have `oldname`s. If the formula doesn't have `oldname`, then the exception is raised.\r\n`Migrator#migrate` performs following steps:\r\n\r\n1. Copy `Cellar/oldname` to `Cellar/newname` if `Cellar/newname` doesn't exist already.\r\n2. Pin `newname` keg if `oldname` was pinned.\r\n3. Unlink oldname keg.\r\n4. Link newname keg.\r\n5. Remove `Cellar/oldname`\r\n6. Create `Cellar/oldname` symlink with `Cellar/newname` target.\r\n7. Create opt link if `oldname` had it.\r\n\r\nIf one of these steps goes wrong, everything rolls back to initial state, which brings us to `migrate` command.\r\n\r\nMigrate\r\n======\r\nIf automatic migration fails, the user have to manually migrate his package.\r\n `brew migrate oldname` is used for that purpose.\r\n\r\nDependencies\r\n===========\r\nWhen the package is renamed there still can be some formulae that depend on `oldname`. If some formula depends on `oldname` we just install `newname`.\r\nIf we install `dependent` that depends on `oldname` and then `oldname` changes its name to `newname` and migrations are performed, then `dependent` keeps working.\r\n\r\nThe following prioritization is used when we instantiate formulae from `depends_on \"name\"`:\r\n    1. Try to load core formula with `name`\r\n    2. Try to load core formula with old name `name`\r\n    3. Try to load tap formula with `name`\r\n    4. Try to load tap formula with old name `name`\r\n\r\nUninstalling\r\n=========\r\nIf we uninstall `newname` after migration, we also remove `oldname` links to `newname`.\r\n\r\nTaps\r\n====\r\nTaps can also be renamed.\r\nThe structure is almost the same as for core formulae.\r\n\r\nEach tap that has renamed formulae must be provided with `formula_renames.json` file with, that stores information about renames in the following format:\r\n```json\r\n{\r\n  \"oldname\": \"newname\"\r\n}\r\n```\r\n\r\nTODOs\r\n======\r\n\r\n- [x] Establish behaviour for changed `ARGV.kegs` and rewrite it if needed.\r\n- [x] Rename formulae from taps.\r\n     - [x] uninstalling\r\n     - [x] dependencies\r\n     - [x] updating\r\n- [x] `brew upgrade newname` now won't relink `oldname`. It's OK.\r\n- [x] unit tests (in progress)\r\n    - [x] tests for migrator exceptions\r\n    - [x] tests for migrator\r\n\r\n`brew migrate` manual tests\r\n=====================\r\n- [x] Migrate core formula\r\n- [x] Migrate tap formula (canonical/fully-qualified) \r\n- [x] Migrate core formula when the same tap formula exists\r\n- [x] Migrate tap formula when the same core one exists\r\n- [x] Migrate tap formula using canonical name\r\n- [x] Migrate tap formula using canonical name, when multiple taps have this formula\r\n- [x] Install formula from path and try to migrate it (MigratorDifferentTapsError is raised)\r\n- [x] Migrate formula, that depends on another\r\n- [x] Migrate library some formula depends on (tested on zint and libpng, itstool and libxml2)\r\n- [x] The same for library formulae \r\n- [x] Dependency on tap oldname :+1: both canonical and fully-qualified names work.\r\n- [x] Dependency on core formula oldname (reinstall zint after renaming libpng)\r\n- [x] Uninstall using oldname (canonical/fully-qualified) `Error: /usr/local/Cellar/ack is a symlink` :+1: \r\n- [x] Uninstall using newname (canonical/fully-qualified) OK :+1: \r\n- [x] Migrating keg_only works.\r\n\r\n*NOTE*\r\nWhat if there are two taps with `newack` formula? (`user/repo/newack` and `user1/repo1/newack`) and we want to `migrate` ack?\r\nBoth repositories have `\"ack\" => \"newack\"` in `TAP_FORMULA_RENAMES` hash.\r\n`brew migrate ack` shows error (`TapFormulaWithOldnameAmbiguityError`) and says that you have to use fully-qualified name. However, if only one tap has \"ack\" renamed, everything is OK.\r\n\r\nChanges\r\n=======\r\n* add `migrate` command.\r\n* add `Migrator` class for handling migrations.\r\n* `uninstall oldname` uninstalls `newname` with `oldname` symlinks.\r\n* `uninstall newname` uninstalls package with its oldname symlinks.\r\n* `update` perform formula renames(migrations) and tap formula renames(migrations) for renamed formulae.\r\n* `update` changes `Tab` if formula migrates to a tap.\r\n* `Formula#oldname` returns oldname for formula.\r\n* `Formulary.from_oldname(ref)` returns formula instance for formula with ref as oldname.\r\n* `FormulaWithOldnameUnavailableError < FormulaUnavailableError` exception if no formula with oldname available.\r\n* `TapFormulaWithOldnameUnavailableError < TapFormulaUnavailableError` same for tap formulae.\r\n* `Formulary#loader_for(ref)` tries to load formula from oldname and from tap oldname.\r\n*`TapLoader` tries to load tap formula from oldname.\r\n*  Add `renamed_formulae` to `extend/ARGV.rb` to instantiate new formulae from old name.\r\n*  `Tap#formula_rename` loads `formula_renames.json` and stores Hash with renames.\r\n* `brew update` updates formulae and perform renames(migrations) for formulae and tap formulae.\r\n* `brew migrate oldname` migrates `oldname` to `newname`.\r\n* `brew audit` warns about dependencies on `oldname`.\r\n* Add `TapFormulaWithOldnameAmbiguityError` exception that is raised when there are multiple tap formulae with given `oldname`.\r\n* Add `test_migrator.rb` tests.\r\n* Add tests for errors in `Migrator`.\r\n\r\nAny feedback/suggestions on the approach and anything else are appreciated.\r\nThanks!","created_at":"2015-06-23T15:37:24Z","updated_at":"2015-08-06T10:33:22Z","closed_at":null,"merged_at":null,"merge_commit_sha":"04b3af91d1917dd50258c577f7c7cb7b6d258e05","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006/commits","review_comments_url":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006/comments","review_comment_url":"https://api.github.com/repos/Homebrew/homebrew/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Homebrew/homebrew/issues/41006/comments","statuses_url":"https://api.github.com/repos/Homebrew/homebrew/statuses/6acefe8885a8129375d7986a43f359f2e15a4854","head":{"label":"vladshablinsky:formula-renames","ref":"formula-renames","sha":"6acefe8885a8129375d7986a43f359f2e15a4854","user":{"login":"vladshablinsky","id":4408920,"avatar_url":"https://avatars.githubusercontent.com/u/4408920?v=3","gravatar_id":"","url":"https://api.github.com/users/vladshablinsky","html_url":"https://github.com/vladshablinsky","followers_url":"https://api.github.com/users/vladshablinsky/followers","following_url":"https://api.github.com/users/vladshablinsky/following{/other_user}","gists_url":"https://api.github.com/users/vladshablinsky/gists{/gist_id}","starred_url":"https://api.github.com/users/vladshablinsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vladshablinsky/subscriptions","organizations_url":"https://api.github.com/users/vladshablinsky/orgs","repos_url":"https://api.github.com/users/vladshablinsky/repos","events_url":"https://api.github.com/users/vladshablinsky/events{/privacy}","received_events_url":"https://api.github.com/users/vladshablinsky/received_events","type":"User","site_admin":false},"repo":{"id":31970155,"name":"homebrew","full_name":"vladshablinsky/homebrew","owner":{"login":"vladshablinsky","id":4408920,"avatar_url":"https://avatars.githubusercontent.com/u/4408920?v=3","gravatar_id":"","url":"https://api.github.com/users/vladshablinsky","html_url":"https://github.com/vladshablinsky","followers_url":"https://api.github.com/users/vladshablinsky/followers","following_url":"https://api.github.com/users/vladshablinsky/following{/other_user}","gists_url":"https://api.github.com/users/vladshablinsky/gists{/gist_id}","starred_url":"https://api.github.com/users/vladshablinsky/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vladshablinsky/subscriptions","organizations_url":"https://api.github.com/users/vladshablinsky/orgs","repos_url":"https://api.github.com/users/vladshablinsky/repos","events_url":"https://api.github.com/users/vladshablinsky/events{/privacy}","received_events_url":"https://api.github.com/users/vladshablinsky/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/vladshablinsky/homebrew","description":":beer: The missing package manager for OS X.","fork":true,"url":"https://api.github.com/repos/vladshablinsky/homebrew","forks_url":"https://api.github.com/repos/vladshablinsky/homebrew/forks","keys_url":"https://api.github.com/repos/vladshablinsky/homebrew/keys{/key_id}","collaborators_url":"https://api.github.com/repos/vladshablinsky/homebrew/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/vladshablinsky/homebrew/teams","hooks_url":"https://api.github.com/repos/vladshablinsky/homebrew/hooks","issue_events_url":"https://api.github.com/repos/vladshablinsky/homebrew/issues/events{/number}","events_url":"https://api.github.com/repos/vladshablinsky/homebrew/events","assignees_url":"https://api.github.com/repos/vladshablinsky/homebrew/assignees{/user}","branches_url":"https://api.github.com/repos/vladshablinsky/homebrew/branches{/branch}","tags_url":"https://api.github.com/repos/vladshablinsky/homebrew/tags","blobs_url":"https://api.github.com/repos/vladshablinsky/homebrew/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/vladshablinsky/homebrew/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/vladshablinsky/homebrew/git/refs{/sha}","trees_url":"https://api.github.com/repos/vladshablinsky/homebrew/git/trees{/sha}","statuses_url":"https://api.github.com/repos/vladshablinsky/homebrew/statuses/{sha}","languages_url":"https://api.github.com/repos/vladshablinsky/homebrew/languages","stargazers_url":"https://api.github.com/repos/vladshablinsky/homebrew/stargazers","contributors_url":"https://api.github.com/repos/vladshablinsky/homebrew/contributors","subscribers_url":"https://api.github.com/repos/vladshablinsky/homebrew/subscribers","subscription_url":"https://api.github.com/repos/vladshablinsky/homebrew/subscription","commits_url":"https://api.github.com/repos/vladshablinsky/homebrew/commits{/sha}","git_commits_url":"https://api.github.com/repos/vladshablinsky/homebrew/git/commits{/sha}","comments_url":"https://api.github.com/repos/vladshablinsky/homebrew/comments{/number}","issue_comment_url":"https://api.github.com/repos/vladshablinsky/homebrew/issues/comments{/number}","contents_url":"https://api.github.com/repos/vladshablinsky/homebrew/contents/{+path}","compare_url":"https://api.github.com/repos/vladshablinsky/homebrew/compare/{base}...{head}","merges_url":"https://api.github.com/repos/vladshablinsky/homebrew/merges","archive_url":"https://api.github.com/repos/vladshablinsky/homebrew/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/vladshablinsky/homebrew/downloads","issues_url":"https://api.github.com/repos/vladshablinsky/homebrew/issues{/number}","pulls_url":"https://api.github.com/repos/vladshablinsky/homebrew/pulls{/number}","milestones_url":"https://api.github.com/repos/vladshablinsky/homebrew/milestones{/number}","notifications_url":"https://api.github.com/repos/vladshablinsky/homebrew/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/vladshablinsky/homebrew/labels{/name}","releases_url":"https://api.github.com/repos/vladshablinsky/homebrew/releases{/id}","created_at":"2015-03-10T17:03:18Z","updated_at":"2015-07-10T15:03:18Z","pushed_at":"2015-08-04T15:18:40Z","git_url":"git://github.com/vladshablinsky/homebrew.git","ssh_url":"git@github.com:vladshablinsky/homebrew.git","clone_url":"https://github.com/vladshablinsky/homebrew.git","svn_url":"https://github.com/vladshablinsky/homebrew","homepage":"http://brew.sh","size":50281,"stargazers_count":0,"watchers_count":0,"language":"Ruby","has_issues":false,"has_downloads":false,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"Homebrew:master","ref":"master","sha":"aea2bd5e2ce77c27e21f7f65d124a7097a9b0489","user":{"login":"Homebrew","id":1503512,"avatar_url":"https://avatars.githubusercontent.com/u/1503512?v=3","gravatar_id":"","url":"https://api.github.com/users/Homebrew","html_url":"https://github.com/Homebrew","followers_url":"https://api.github.com/users/Homebrew/followers","following_url":"https://api.github.com/users/Homebrew/following{/other_user}","gists_url":"https://api.github.com/users/Homebrew/gists{/gist_id}","starred_url":"https://api.github.com/users/Homebrew/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Homebrew/subscriptions","organizations_url":"https://api.github.com/users/Homebrew/orgs","repos_url":"https://api.github.com/users/Homebrew/repos","events_url":"https://api.github.com/users/Homebrew/events{/privacy}","received_events_url":"https://api.github.com/users/Homebrew/received_events","type":"Organization","site_admin":false},"repo":{"id":206084,"name":"homebrew","full_name":"Homebrew/homebrew","owner":{"login":"Homebrew","id":1503512,"avatar_url":"https://avatars.githubusercontent.com/u/1503512?v=3","gravatar_id":"","url":"https://api.github.com/users/Homebrew","html_url":"https://github.com/Homebrew","followers_url":"https://api.github.com/users/Homebrew/followers","following_url":"https://api.github.com/users/Homebrew/following{/other_user}","gists_url":"https://api.github.com/users/Homebrew/gists{/gist_id}","starred_url":"https://api.github.com/users/Homebrew/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Homebrew/subscriptions","organizations_url":"https://api.github.com/users/Homebrew/orgs","repos_url":"https://api.github.com/users/Homebrew/repos","events_url":"https://api.github.com/users/Homebrew/events{/privacy}","received_events_url":"https://api.github.com/users/Homebrew/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Homebrew/homebrew","description":":beer: The missing package manager for OS X.","fork":false,"url":"https://api.github.com/repos/Homebrew/homebrew","forks_url":"https://api.github.com/repos/Homebrew/homebrew/forks","keys_url":"https://api.github.com/repos/Homebrew/homebrew/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Homebrew/homebrew/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Homebrew/homebrew/teams","hooks_url":"https://api.github.com/repos/Homebrew/homebrew/hooks","issue_events_url":"https://api.github.com/repos/Homebrew/homebrew/issues/events{/number}","events_url":"https://api.github.com/repos/Homebrew/homebrew/events","assignees_url":"https://api.github.com/repos/Homebrew/homebrew/assignees{/user}","branches_url":"https://api.github.com/repos/Homebrew/homebrew/branches{/branch}","tags_url":"https://api.github.com/repos/Homebrew/homebrew/tags","blobs_url":"https://api.github.com/repos/Homebrew/homebrew/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Homebrew/homebrew/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Homebrew/homebrew/git/refs{/sha}","trees_url":"https://api.github.com/repos/Homebrew/homebrew/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Homebrew/homebrew/statuses/{sha}","languages_url":"https://api.github.com/repos/Homebrew/homebrew/languages","stargazers_url":"https://api.github.com/repos/Homebrew/homebrew/stargazers","contributors_url":"https://api.github.com/repos/Homebrew/homebrew/contributors","subscribers_url":"https://api.github.com/repos/Homebrew/homebrew/subscribers","subscription_url":"https://api.github.com/repos/Homebrew/homebrew/subscription","commits_url":"https://api.github.com/repos/Homebrew/homebrew/commits{/sha}","git_commits_url":"https://api.github.com/repos/Homebrew/homebrew/git/commits{/sha}","comments_url":"https://api.github.com/repos/Homebrew/homebrew/comments{/number}","issue_comment_url":"https://api.github.com/repos/Homebrew/homebrew/issues/comments{/number}","contents_url":"https://api.github.com/repos/Homebrew/homebrew/contents/{+path}","compare_url":"https://api.github.com/repos/Homebrew/homebrew/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Homebrew/homebrew/merges","archive_url":"https://api.github.com/repos/Homebrew/homebrew/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Homebrew/homebrew/downloads","issues_url":"https://api.github.com/repos/Homebrew/homebrew/issues{/number}","pulls_url":"https://api.github.com/repos/Homebrew/homebrew/pulls{/number}","milestones_url":"https://api.github.com/repos/Homebrew/homebrew/milestones{/number}","notifications_url":"https://api.github.com/repos/Homebrew/homebrew/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Homebrew/homebrew/labels{/name}","releases_url":"https://api.github.com/repos/Homebrew/homebrew/releases{/id}","created_at":"2009-05-20T19:38:37Z","updated_at":"2015-08-06T09:49:48Z","pushed_at":"2015-08-06T09:26:32Z","git_url":"git://github.com/Homebrew/homebrew.git","ssh_url":"git@github.com:Homebrew/homebrew.git","clone_url":"https://github.com/Homebrew/homebrew.git","svn_url":"https://github.com/Homebrew/homebrew","homepage":"http://brew.sh","size":1582315,"stargazers_count":24502,"watchers_count":24502,"language":"Ruby","has_issues":true,"has_downloads":false,"has_wiki":true,"has_pages":true,"forks_count":12296,"mirror_url":null,"open_issues_count":408,"forks":12296,"open_issues":408,"watchers":24502,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006"},"html":{"href":"https://github.com/Homebrew/homebrew/pull/41006"},"issue":{"href":"https://api.github.com/repos/Homebrew/homebrew/issues/41006"},"comments":{"href":"https://api.github.com/repos/Homebrew/homebrew/issues/41006/comments"},"review_comments":{"href":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006/comments"},"review_comment":{"href":"https://api.github.com/repos/Homebrew/homebrew/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Homebrew/homebrew/pulls/41006/commits"},"statuses":{"href":"https://api.github.com/repos/Homebrew/homebrew/statuses/6acefe8885a8129375d7986a43f359f2e15a4854"}}}}