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

PropertyReturnsDescription
repositoriesList<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.
repositoryCategoriesList<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.

ParameterDescription
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.

ParameterDescription
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.

ParameterDescription
repoNamethe name of the repository to find or create
branchNamethe name of the branch to find or create within the repository, or blank for the live branch
autoCreatewhen 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.

ParameterDescription
appNamethe repository and app name. Letters, digits and hyphens only, lower case by convention
titlethe display title shown wherever the app is listed
appProvidertrue if the repository provides a directly installable app
themeProvidertrue if it provides a website theme
recipeProvidertrue 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.

ParameterDescription
bthe branch whose file system is modified
paththe directory path to ensure exists
currentUserthe 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.

ParameterDescription
branchthe branch containing the target directory
dirPaththe path of the directory that already contains, or will contain, the file
filenamethe name of the file to create or update
inthe file content to upload
currentUserthe 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).

ParameterDescription
branchthe branch to read from
dirPaththe path of the directory containing the file
filenamethe 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.

ParameterDescription
branchthe branch containing the controllers.xml file, eg an app's or a website's
controllersDirPaththe directory containing controllers.xml, eg "/APP-INF" for an app or "/WEB-INF" for a website
appPaththe path used to namespace the component's declared files, eg "myApp/components"
compIdthe globally unique component id
typesthe resource types this component is compatible with, eg ["html"]
desca user friendly description of the component
categoriescategories or tags for this component
overwritewhen true, replaces any existing component with the same id
currentUserthe 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.

ParameterDescription
branchthe branch containing the file
dirPaththe path of the directory containing the file
filenamethe name of the file to delete
currentUserthe 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.

ParameterDescription
inthe 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.

ParameterDescription
inthe 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.

ParameterDescription
branchthe branch to walk
callbackinvoked 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.

ParameterDescription
b1the branch considered the current state
b2the 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.

ParameterDescription
c1the commit considered the current state
c2the 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.

ParameterDescription
bthe branch containing the node
dataNodethe 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.

ParameterDescription
branchthe 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.

ParameterDescription
idthe 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.

ParameterDescription
namethe name of the repository category to find

createRepositoryCategory(String title, String name)

Returns: RepositoryCategory

Creates a new repository category for the current tenant organisation.

ParameterDescription
titlethe display title for the category
namethe unique, path-safe name for the category

deleteRepositoryCategory(RepositoryCategory category)

Returns: void

Deletes a repository category and flushes the change immediately.

ParameterDescription
categorythe 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.

ParameterDescription
repositorythe repository to update
categorythe 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.

ParameterDescription
repositorythe 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.

ParameterDescription
branchthe branch to check
To get full access to the Kademi Hub existing customers can login here, or new customers can register here.