/* (non-Javadoc) * @see com.buildml.main.ICliCommand#invoke(com.buildml.model.BuildStore, java.lang.String[]) */ @Override public void invoke(IBuildStore buildStore, String buildStorePath, String[] args) { CliUtils.validateArgs( getName(), args, 2, 2, "You must specify a package name and a colon-separated list of action-specs."); IPackageMemberMgr pkgMemberMgr = buildStore.getPackageMemberMgr(); IActionMgr actionMgr = buildStore.getActionMgr(); /* * The package can be of the form: "pkg". There is no scope value allowed * for actions. */ String pkgName = args[0]; int pkgAndScopeIds[] = CliUtils.parsePackageAndScope(buildStore, pkgName, false); int pkgId = pkgAndScopeIds[0]; /* compute the ActionSet from the user-supplied list of action-specs */ String actionSpecs = args[1]; ActionSet actionsToSet = CliUtils.getCmdLineActionSet(actionMgr, actionSpecs); /* now visit each action in the ActionSet and set its package */ boolean prevState = buildStore.setFastAccessMode(true); for (int actionId : actionsToSet) { pkgMemberMgr.setPackageOfMember(IPackageMemberMgr.TYPE_ACTION, actionId, pkgId); } buildStore.setFastAccessMode(prevState); }
/** * Given an actionId, move the action, and possibly all its predecessors to the new package. If * necessary, an output file group is created and also moved to the new package. So too are all * the files in that groups. * * @param actionId ID of the action to be moved. * @return ID of the output file group, or ErrorCode.NOT_FOUND if there's no output group. * @throws CanNotRefactorException If something goes wrong. */ private int moveActionToPackage(int actionId) throws CanNotRefactorException { /* first, check to see if this action is already imported this package - if so, we're done */ Object existingMap = actionCache.get(Integer.valueOf(actionId)); if (existingMap instanceof Integer) { return (Integer) existingMap; } /* validate that the action is atomic */ Integer children[] = actionMgr.getChildren(actionId); if (children.length != 0) { throw new CanNotRefactorException(Cause.ACTION_NOT_ATOMIC, actionId); } /* * The action is not yet imported, and it is atomic. Figure out its current package * and prepare to move it to the new package. */ int fileGroupId = ErrorCode.NOT_FOUND; PackageDesc desc = pkgMemberMgr.getPackageOfMember(IPackageMemberMgr.TYPE_ACTION, actionId); if (desc == null) { throw new FatalError("Can't retrieve action's current package"); } /* Create UndoOp for changing the action's package */ ActionUndoOp actionOp = new ActionUndoOp(buildStore, actionId); actionOp.recordPackageChange(desc.pkgId, destPkgId); multiOp.add(actionOp); /* Create a new file group containing all the files that this action generates */ Integer writtenFiles[] = actionMgr.getFilesAccessed(actionId, OperationType.OP_WRITE); if (writtenFiles.length > 0) { fileGroupId = createSourceFileGroup(Arrays.asList(writtenFiles)); /* Connect the "output" slot from the action to this new file group */ ActionUndoOp slotOp = new ActionUndoOp(buildStore, actionId); slotOp.recordSlotChange(IActionMgr.OUTPUT_SLOT_ID, null, fileGroupId); multiOp.add(slotOp); } /* compute/generate/move all the predecessor actions or file groups */ computeInputActions(actionId); /* * Store actionId/fileGroupId in our cache, to avoid doing this import again * and ending up with multiple output file groups when only one is required. */ actionCache.put(actionId, fileGroupId); /* return the ID of the output file group */ return fileGroupId; }
/** * Given a list of file IDs, create a new source file group and schedule the members to be added * to it (by appending to the multiOp). In addition to moving the file group into the destination * package, all the individual files are also moved. If any files are not within the source root, * throw a {@link CanNotRefactorException} with cause code of PATH_OUT_OF_RANGE. * * @param members A list of file IDs to be added to the file group. * @return The ID of the newly-created file group. * @throws CanNotRefactorException Something went wrong during the refactoring. */ private int createSourceFileGroup(List<Integer> members) throws CanNotRefactorException { /* * Create the new fileGroup. Even though we won't populate it until the multiOp * is executed, we must still allocate a new fileGroup ID number. */ int fileGroupId = fileGroupMgr.newSourceGroup(destPkgId); if (fileGroupId < 0) { throw new FatalError("Unable to create new file group"); } FileGroupUndoOp op = new FileGroupUndoOp(buildStore, fileGroupId); op.recordMembershipChange(new ArrayList<Integer>(), members); multiOp.add(op); /* * Move all the files into the destination package, using FileUndoOps. Before * a file can be moved, we must ensure that it's within the source root of the package. */ List<Integer> filesOutOfRange = new ArrayList<Integer>(); /* * For each loose file, validate if it's within the package roots, and if so, * schedule an UndoOp to make the necessary change. If not, throw an exception. */ for (int pathId : members) { PackageDesc oldDesc = pkgMemberMgr.getPackageOfMember(IPackageMemberMgr.TYPE_FILE, pathId); if (oldDesc == null) { throw new FatalError("Can't find pathId"); } /* * Check that this path is within the source root. If so, schedule it to be move to * the destination package. */ if (fileMgr.isAncestorOf(pkgRootId, pathId)) { FileUndoOp pkgChangeOp = new FileUndoOp(buildStore, pathId); pkgChangeOp.recordChangePackage( oldDesc.pkgId, oldDesc.pkgScopeId, destPkgId, IPackageMemberMgr.SCOPE_PRIVATE); multiOp.add(pkgChangeOp); } /* * Else, record this pathID as being out of range. We'll report an exception * once we've collected the complete list of invalid paths. */ else { filesOutOfRange.add(pathId); } } /* * If any files were out of range, throw an exception. */ if (filesOutOfRange.size() > 0) { throw new CanNotRefactorException( Cause.PATH_OUT_OF_RANGE, filesOutOfRange.toArray(new Integer[0])); } /* update the cache, with the members that the file group will contain (once the multiOp is executed) */ fileGroupCache.put(fileGroupId, members); return fileGroupId; }