Manages the hashsplit4j-backed content repositories used to store website, app and other branch-versioned file content across the platform. Provides branch and commit operations such as create, copy, set-to-hash and diff, file read/write/delete within a branch's virtual file system, and repository category management, plus blob integrity verification against the hash and blob stores. A subset of methods is exported to GraalJS app scripts as the repository API for reading, writing and deleting files, such as maintaining a component declaration in controllers.xml.
Group: Managers
Properties
| Property | Returns | Description |
|---|---|---|
| repositories | List<Repository> | All repositories belonging to the current tenant organisation, including websites, apps and other repository-backed resources. Includes soft-deleted repositories, since the result is not filtered by deletion state. |
| repositoryCategories | List<RepositoryCategory> | All repository categories defined for the current tenant organisation, used to group and organise repositories in the admin UI. |
Methods
getBranchHash(Branch branch) · setBranchToHash(Branch branch, String hash) · findOrCreateRepositoryBranch(String repoName, String branchName, boolean autoCreate) · createAppRepository(String appName, String title, boolean appProvider, boolean themeProvider, boolean recipeProvider) · createDirectoryIfMissing(Branch b, Path path, Profile currentUser) · saveFile(Branch branch, String dirPath, String filename, InputStream in, Profile currentUser) · getFileContent(Branch branch, String dirPath, String filename) · upsertComponentInControllersXml(Branch branch, String controllersDirPath, String appPath, String compId, List<String> types, String desc, String categories, boolean overwrite, Profile currentUser) · deleteFile(Branch branch, String dirPath, String filename, Profile currentUser) · upload(InputStream in) · parse(InputStream in) · walkFiles(Branch branch, Consumer callback) · diff(Branch b1, Branch b2) · diff(Commit c1, Commit c2) · parseHtml(Branch b, DataNode dataNode) · commitHashCleanup(Branch branch) · getRepositoryCategories() · findRepositoryCategory(Long id) · findRepositoryCategory(String name) · createRepositoryCategory(String title, String name) · deleteRepositoryCategory(RepositoryCategory category) · setCategoryForRepository(Repository repository, RepositoryCategory category) · deleteRepository(Repository repository) · getRepositories() · getAppInitStatus(Branch branch)
getBranchHash(Branch branch)
Returns: String
Returns the tree hash (item hash) of the branch's current head commit, ie the hash identifying the exact state of the whole branch. This is the value used for "set hash" style whole-repo deployment.
| Parameter | Description |
|---|---|
branch | - the branch to read |
setBranchToHash(Branch branch, String hash)
Returns: boolean
Sets the given branch's head to point at the given tree hash, mirroring the "set hash" deployment used for websites/repositories. Creates a new commit at the hash and makes it the branch head, replacing the entire branch content atomically (so adds, edits and deletes are all applied). This does NOT fetch the underlying blobs - callers deploying from a remote account must first pull the tree, eg via ApplyConfigContext.fetchRemoteDir.
| Parameter | Description |
|---|---|
branch | - the branch to update |
hash | - the new tree/item hash to point the branch head at |
findOrCreateRepositoryBranch(String repoName, String branchName, boolean autoCreate)
Returns: Branch
Finds the named repository and branch, optionally creating either or both if they do not exist. When branchName is blank, the repository's live branch is returned instead of looking up a named branch.
| Parameter | Description |
|---|---|
repoName | the name of the repository to find or create |
branchName | the name of the branch to find or create within the repository, or blank for the live branch |
autoCreate | when true, creates the repository and/or branch if missing; when false, returns null instead |
createAppRepository(String appName, String title, boolean appProvider, boolean themeProvider, boolean recipeProvider)
Returns: AppRepository
Creates a new app repository on the current account - the same thing the Add new app form on the apps admin page creates. The new repository is EMPTY: AppRepository.CONTENT_HASH is commented "repoapp template" but is the hash of an empty tree, so what it gives the TRUNK branch is a valid first commit and no files. The caller writes /APP-INF/controllers.xml and everything else, and the app still has to be enabled on a website before anything it registers runs. What a repository provides is declared by three flags, and the four kinds people talk about map onto them like this. An APP is a directly installable unit, offered to users as something they can add to a website. A THEME supplies a website's stylesheets and theme templates, is normally one per website, and usually depends on bootstrap-base. A RECIPE is a solution builder, used by the solution wizard to create one or more fully configured websites. A LIB is only ever a dependency of an app, and is declared by providing NONE of the other three rather than by a flag of its own.
| Parameter | Description |
|---|---|
appName | the repository and app name. Letters, digits and hyphens only, lower case by convention |
title | the display title shown wherever the app is listed |
appProvider | true if the repository provides a directly installable app |
themeProvider | true if it provides a website theme |
recipeProvider | true if it provides a solution builder recipe |
createDirectoryIfMissing(Branch b, Path path, Profile currentUser)
Returns: void
Walks the given path within a branch's virtual file system, creating any missing directories along the way, then saves the change. Use formatter.toPath() to build the path argument.
| Parameter | Description |
|---|---|
b | the branch whose file system is modified |
path | the directory path to ensure exists |
currentUser | the profile the change is attributed to |
saveFile(Branch branch, String dirPath, String filename, InputStream in, Profile currentUser)
Returns: void
Creates or overwrites a file within an existing directory of a branch's virtual file system, uploading the given content and saving the change.
| Parameter | Description |
|---|---|
branch | the branch containing the target directory |
dirPath | the path of the directory that already contains, or will contain, the file |
filename | the name of the file to create or update |
in | the file content to upload |
currentUser | the profile the change is attributed to |
getFileContent(Branch branch, String dirPath, String filename)
Returns: String
Reads the current text content of an existing file, for read-modify-write workflows (eg reading controllers.xml before adding a component declaration and saving it back with saveFile).
| Parameter | Description |
|---|---|
branch | the branch to read from |
dirPath | the path of the directory containing the file |
filename | the name of the file within dirPath |
upsertComponentInControllersXml(Branch branch, String controllersDirPath, String appPath, String compId, List<String> types, String desc, String categories, boolean overwrite, Profile currentUser)
Returns: String
Adds or replaces a component declaration directly in a controllers.xml file, as an alternative to declaring it via a controllerMappings.addComponent(...) call in JS source. File paths for the component's render template, settings template and settings JS are derived by the same naming convention used by ComponentBean.add. If controllers.xml does not already exist at controllersDirPath, a new one is created there, auto-creating controllersDirPath itself first if needed.
| Parameter | Description |
|---|---|
branch | the branch containing the controllers.xml file, eg an app's or a website's |
controllersDirPath | the directory containing controllers.xml, eg "/APP-INF" for an app or "/WEB-INF" for a website |
appPath | the path used to namespace the component's declared files, eg "myApp/components" |
compId | the globally unique component id |
types | the resource types this component is compatible with, eg ["html"] |
desc | a user friendly description of the component |
categories | categories or tags for this component |
overwrite | when true, replaces any existing component with the same id |
currentUser | the profile to attribute the change to |
deleteFile(Branch branch, String dirPath, String filename, Profile currentUser)
Returns: void
Deletes a file from a branch's virtual file system if it exists, and saves the change. Does nothing if the file is already absent.
| Parameter | Description |
|---|---|
branch | the branch containing the file |
dirPath | the path of the directory containing the file |
filename | the name of the file to delete |
currentUser | the profile the change is attributed to |
upload(InputStream in)
Returns: String
Uploads content to the platform's blob and hash stores, chunking and hashing it via the hashsplit4j parser, and returns the resulting content hash. Unlike saveFile, this only persists the blob data - it does not attach the result to any file or directory node.
| Parameter | Description |
|---|---|
in | the content to upload |
parse(InputStream in)
Returns: String
Computes the content hash of the given stream using the hashsplit4j parser, without persisting any blobs or chunks. Use this to compute a hash for comparison without the cost of an upload.
| Parameter | Description |
|---|---|
in | the content to hash |
walkFiles(Branch branch, Consumer callback)
Returns: void
Walks every file and directory within the given branch's virtual file system, depth first, invoking the callback once for each node with either a FileNode or a DirectoryNode as the argument. For each FileNode the callback can call parseHtml to convert it into the conventional property form used for search indexing.
| Parameter | Description |
|---|---|
branch | the branch to walk |
callback | invoked once for each file or directory node encountered |
diff(Branch b1, Branch b2)
Returns: Map<Path,String>
Compares the head commits of two branches, treating the first branch as the current state and the second as the state being compared against. The result maps each changed path to a short textual description of the change, such as created file, updated file or deleted directory.
| Parameter | Description |
|---|---|
b1 | the branch considered the current state |
b2 | the branch being compared against |
diff(Commit c1, Commit c2)
Returns: Map<Path,String>
Compares two commits, treating the first as the current state and the second as the state being compared against. The result maps each changed path to a short textual description of the change, such as created file, updated file or deleted directory.
| Parameter | Description |
|---|---|
c1 | the commit considered the current state |
c2 | the commit being compared against |
parseHtml(Branch b, DataNode dataNode)
Returns: MapBuilder
Builds a conventional property map for a file or directory node, such as is used for search indexing, extracting the page title, body content, target groups, item type, tags and category from an HTML page's parameters. For a directory node, or a file that is not an HTML page, only the name, parent name, repository, branch and path fields are set.
| Parameter | Description |
|---|---|
b | the branch containing the node |
dataNode | the file or directory node to build properties for |
commitHashCleanup(Branch branch)
Returns: void
Reconciles a website branch's app dependencies after its commit hash has been set: for each app declared as enabled in the branch's website settings, installs the app, or the specific version required, if it is not already installed, then re-applies the branch's public theme. Has no effect on branches whose repository is not a website.
| Parameter | Description |
|---|---|
branch | the branch to reconcile |
getRepositoryCategories()
Returns: List<RepositoryCategory>
All repository categories defined for the current tenant organisation, used to group and organise repositories in the admin UI.
findRepositoryCategory(Long id)
Returns: RepositoryCategory
Finds a repository category belonging to the current tenant organisation by its id.
| Parameter | Description |
|---|---|
id | the id of the repository category to find |
findRepositoryCategory(String name)
Returns: RepositoryCategory
Finds a repository category belonging to the current tenant organisation by its name.
| Parameter | Description |
|---|---|
name | the name of the repository category to find |
createRepositoryCategory(String title, String name)
Returns: RepositoryCategory
Creates a new repository category for the current tenant organisation.
| Parameter | Description |
|---|---|
title | the display title for the category |
name | the unique, path-safe name for the category |
deleteRepositoryCategory(RepositoryCategory category)
Returns: void
Deletes a repository category and flushes the change immediately.
| Parameter | Description |
|---|---|
category | the repository category to delete |
setCategoryForRepository(Repository repository, RepositoryCategory category)
Returns: void
Sets the category a repository belongs to. If category is null, the repository is removed from any category.
| Parameter | Description |
|---|---|
repository | the repository to update |
category | the category to assign, or null to clear the repository's category |
deleteRepository(Repository repository)
Returns: void
Soft deletes a repository. If the repository is a website, also fires a WebsiteDeletedEvent. Only permitted when the current root folder is an organisation root folder.
| Parameter | Description |
|---|---|
repository | the repository to soft delete |
getRepositories()
Returns: List<Repository>
All repositories belonging to the current tenant organisation, including websites, apps and other repository-backed resources. Includes soft-deleted repositories, since the result is not filtered by deletion state.
getAppInitStatus(Branch branch)
Returns: Map<String,Object>
Whether the apps in a branch loaded, and what they said while loading. <p> This is the check that turns writing code into changing behaviour. An app's scripts are parsed and its registrations run when it initialises; if that fails it does not half work, it does not load, and everything it registered silently disappears. The symptom is a missing menu item or a page that 404s, a long way from the cause. The platform records what happened and {@code devTools} has always shown it - this makes the same record reachable from a script, so a caller that has just written a file can find out whether it broke the app rather than reporting that it wrote a file. <p> Nothing needs invalidating first. Mappings are cached against the branch's tree hash, so a write has already changed the key and the next read reparses on its own. <p> The account's queries repository loads through an entirely different mechanism and is answered by {@link #getQueriesRepoInitStatus}, so that a script that fails to parse there is reported rather than read as a repository that registers nothing.
| Parameter | Description |
|---|---|
branch | the branch to check |