|  | # Working With Files | 
|  |  | 
|  | Adding, removing, and renaming files in iOS Chromium needs to follow a specific | 
|  | procedure that will be unfamiliar to engineers coming from other iOS projects. | 
|  | Conceptually, every file is recorded in _four_ locations: the local filesystem, | 
|  | git, the `BUILD.gn` files, and the XCode projects. Of these, the XCode project | 
|  | is wholly generated from the others. | 
|  |  | 
|  | [TOC] | 
|  |  | 
|  | ## Overview | 
|  |  | 
|  | **Do not use XCode to manipulate files.** The XCode project used for iOS | 
|  | Chromium is _generated_; it's functionally a build artifact. The various | 
|  | `BUILD.gn` files in Chromium define structure of the XCode project file. Running | 
|  | `gclient runhooks` causes the project files to be regenerated. | 
|  |  | 
|  | Individual files can have their contents edited within XCode, and all of the | 
|  | regular testing and debugging activities can be done within XCode. It just can't | 
|  | be used to create files, rename files, delete files, or manipulate the project | 
|  | group structure in any way. To do these things, follow the procedures below. | 
|  |  | 
|  | ## Adding files | 
|  |  | 
|  | To add any files (new headers, `.mm` or `.cc` implementation files, asset files | 
|  | of any kind), the following general steps need to happen: | 
|  |  | 
|  | 1.  The file needs to exist in the correct directory of the file system for your | 
|  | Chromium checkout. New files need to be created, or assets need to be | 
|  | copied to the right location. | 
|  |  | 
|  | 1.  The new files need to be added to git. | 
|  |  | 
|  | 1.  The new files need to be added to a target in a `BUILD.gn` file (usually in | 
|  | the same directory as the newly added file). | 
|  |  | 
|  | 1.  The XCode project needs to be regenerated. | 
|  |  | 
|  | For adding new header or implementation files, the following procedure is | 
|  | recommended: | 
|  |  | 
|  | 1.  Generate the new files using `tools/boilerplate.py`. This will generate | 
|  | header guard macros and include the copyright boilerplate. Make sure to run | 
|  | this from root (`src/`) so the header guards include the correct, full | 
|  | path. | 
|  |  | 
|  | 2.  Add the newly created files using `git add`. | 
|  |  | 
|  | 3.  Edit the `BUILD.gn` file for the directory where the files were added. For | 
|  | each file, add it to the `sources` list for the correct `source_set` in the | 
|  | `BUILD.gn` file. Note that `gn format` (which is run as part of `git cl | 
|  | format`) will take care of alphabetizing the lists along with other | 
|  | formatting, so there's no need to manually do these things. (`BUILD.gn` | 
|  | files cand be edited directly in XCode, or in another editor such as `vi`). | 
|  |  | 
|  | 4.  Once all of the files have been created, `add`ed and all `BUILD.gn` files | 
|  | have been updated, run `gclient runhooks` to regenerate all XCode projects. | 
|  |  | 
|  | 5.  If XCode is open, it may prompt to "Autocreate Schemes". If so, click on the | 
|  | highlighted "Automatically Create Schemes" button. | 
|  |  | 
|  | In the shell, this procedure would look like this: | 
|  | ```bash | 
|  | // Step 1 -- generate new files. | 
|  | $ tools/boilerplate.py ios/chrome/browser/some_feature/feature_class.h | 
|  | $ tools/boilerplate.py ios/chrome/browser/some_feature/feature_class.mm | 
|  | $ tools/boilerplate.py ios/chrome/browser/some_feature/feature_class_unittest.mm | 
|  | // Step 2 -- add the new files. | 
|  | $ git add ios/chrome/browser/some_feature/feature_class* | 
|  | // Step 3 -- edit the BUILD.gn file in the editor of your choice | 
|  | $ vi ios/chrome/browser/some_feature/BUILD.gn | 
|  | // Step 4 -- regenerate the XCode Projects | 
|  | $ gclient runhooks | 
|  | ``` | 
|  |  | 
|  | To add asset files, follow this procedure: | 
|  |  | 
|  | 1.  Copy the asset files to the correct directory, with the correct names | 
|  | (including `@2x` and `@3x` suffixes) Note that images are stored in | 
|  | `.imageset` directories, conventionally inside `resources` directories for a | 
|  | given UI feature. New directories, if needed, are created in the usual way | 
|  | (`mkdir`). Note that there is no equivalent of `boilerplate.py` for images | 
|  | or other asset files. | 
|  |  | 
|  | 1.  Create or copy `Contents.json` files for each new `.imageset` directory, | 
|  | with the appropriate contents. | 
|  |  | 
|  | 1.  Add all image and `Contents.json` files using `git add`. | 
|  |  | 
|  | 1.  Edit the `BUILD.gn` file in the containing `resources` directory, adding | 
|  | `imageset` entries for each added `.imageset` directory, and then grouping | 
|  | all assets into a new or existing `group()` declaration with a `public_deps` | 
|  | list containing all of the `imageset` targets. | 
|  |  | 
|  | 1.  Regenerate the XCode project with `gclient runhooks`. | 
|  |  | 
|  | To add Markdown documentation files, the procedure is much simpler. These files | 
|  | are automatically added to the XCode project without `BUILD.gn` entries, and | 
|  | they have no required boilerplate. So adding new docs is as simple as: | 
|  |  | 
|  | 1.  Create a new `.md` file in the appropriate directory (`docs/ios`, for | 
|  | example). | 
|  |  | 
|  | 1. `git add` the file. | 
|  |  | 
|  | The newly added file will be visible in XCode after the next `gclient runhooks`. | 
|  |  | 
|  | ## Moving and renaming files. | 
|  |  | 
|  | Renaming a file involves updating the filename in all of the places where it | 
|  | exists: the file names in the filesystem, the file names in git, header guards | 
|  | in files, import declarations in files, listings in BUILD.gn files, and | 
|  | internally in the XCode project. As with adding a file, different tools are used | 
|  | for each of these. Unlike creating a file, which starts with actually adding a | 
|  | file to the filesystem, a rename starts with updating git (via `git mv`), then | 
|  | using the `mass-rename` tool to update file contents. | 
|  |  | 
|  | `tools/git/mass-rename.py` works by looking at _uncommitted_ file moves in git, | 
|  | and then updating all includes, header guards, and BUILD.gn entries to use the | 
|  | new name. It doesn't update some other files, such as `Contents.json` files for | 
|  | image assets. It also doesn't change any symbols in code, so class and variable | 
|  | names won't be changed. | 
|  |  | 
|  | For many file moves, it will be simpler to use another tool, | 
|  | `tools/git/move_source_file.py`, which combines `git mv` and `mass-rename` in a | 
|  | single action. For example, renaming `feature_class` to `renamed_class` would be | 
|  | done like this: | 
|  | ```bash | 
|  | $ tools/git/move_source_file.py ios/chrome/browser/some_feature/feature_class.h \ | 
|  | ios/chrome/browser/some_feature/renamed_class.h | 
|  | $ tools/git/move_source_file.py ios/chrome/browser/some_feature/feature_class.mm \ | 
|  | ios/chrome/browser/some_feature/renamed_class.mm | 
|  | ``` | 
|  |  | 
|  | The step-by-step procedure for a rename is: | 
|  |  | 
|  | 1.  If there are other uncommitted changes before the move, it's usually | 
|  | cleanest to commit before starting the move. | 
|  |  | 
|  | 1.  `move_source_file` each file that needs to be renamed. This renames the file | 
|  | in both the file system and in git, and in most places where it's used in | 
|  | code. | 
|  |  | 
|  | 1.  Run `gclient runhooks` to update the XCode project. Check that all of the | 
|  | needed name changes have been made (for example, by building all targets). | 
|  | Make any other needed fixes. | 
|  |  | 
|  | 1.  If any classes or other symbols need to be renamed (remember that the name | 
|  | of the primary interface in each file must match the file name), make those | 
|  | changes. Find-and-replace tools like `tools/git/mffr.py` or XCode's | 
|  | Find/Replace can help here, but there are no compiler-aware tools that can | 
|  | do a "smart" rename. | 
|  |  | 
|  | 1.  Commit all changes (`git commit -a -m <your comment>`). | 
|  |  | 
|  | A move—where a file is moved to a different directory—is in most respects | 
|  | performed using the same steps as a rename. However, while `mass-rename.py` (and | 
|  | thus `move_source_file.py`) will update existing file names in `BUILD.gn` files, | 
|  | it won't move entries from one `BUILD.gn` file to another. To move files to a | 
|  | different directory, the preceding procedure is used, but between steps 2 and 3 | 
|  | (after moving the files, but before regenerating the XCode project), the old | 
|  | filenames will need to be removed from the `BUILD.gn` files in the old | 
|  | directories and added to the `BUILD.gn` files in the new directories. | 
|  |  | 
|  | Also note that while `move_source_file` must be used separately for each file | 
|  | being renamed within a directory, it (just like `git mv`) can move multiple | 
|  | files without renaming to a new directory in a single command: | 
|  |  | 
|  | ```bash | 
|  | $ tools/git/mass-rename.py ios/chrome/browser/some_feature/feature_class.* \ | 
|  | ios/chrome/browser/some_feature/feature_class_unittest.mm \ | 
|  | ios/chrome/browser/other_feature/ | 
|  | ``` | 
|  |  | 
|  | ## Deleting files. | 
|  |  | 
|  | Deleting files follows the same patterns as adding and moving files. As with a | 
|  | file move, it's best to begin with deleting the files from git. | 
|  |  | 
|  | Typically, before actually removing a file, first all usage of the interface(s) | 
|  | in the file(s) will be removed, and the file will no longer be `#imported` | 
|  | anywhere. | 
|  |  | 
|  | Step-by step: | 
|  |  | 
|  | 1.  `git rm` the files you want to remove. This will also remove the files | 
|  | from the filesystem. | 
|  |  | 
|  | 1.  Manually remove the `BUILD.gn` entries for the files. | 
|  |  | 
|  | 1.  Regenerate the XCode project (with `gclient runhooks`) to remove the files | 
|  | from XCode. | 
|  |  | 
|  | ## Finally. | 
|  |  | 
|  | It's easy to miss some uses of a file that was renamed or deleted, and fixing | 
|  | compilation errors discovered in the commit queue means another | 
|  | commit-upload-dry run cycle (at least). To minimize this, after any change that | 
|  | adds, renames, moves, or deletes files, be sure to take the following steps: | 
|  |  | 
|  | 1.  `git cl format` to update the formatting of all files. | 
|  |  | 
|  | 1.  `gn check` to make sure that any new or moved files follow the dependency | 
|  | rules (for example: `gn check -C out/Debug-iphonesimulator/`). | 
|  |  | 
|  | 1.  Build all targets, to make sure that everything has been added, changed, or | 
|  | removed correctly. This can be done by selecting the "All" target in XCode | 
|  | and building (`⌘-B`), or from the command line (for example, `autoninja -C | 
|  | out/Debug-iphonesimulator/`). | 
|  |  | 
|  | Changes that involve adding or deleting more than a few files, and most renames | 
|  | of any size, should be in a single CL with no other changes, for ease of | 
|  | reviewing and (if necessary) reverting or cherry-picking. | 
|  |  | 
|  | ## Recovering from accidental XCode Project usage. | 
|  |  | 
|  | If files are accidentally added, renamed, or moved through XCode, other settings | 
|  | in the XCode project may be changed that will introduce strange local build | 
|  | failures. In this case, take the following steps to recover. | 
|  |  | 
|  | 1. Quit XCode. | 
|  |  | 
|  | 1. Delete all generated XCode projects and associated files: `rm -rf out/build`. | 
|  |  | 
|  | 1. Regenerate all XCode projects: `gclient runhooks`. |