'red', // Red 1 => 'yellow', // Orange 2 => 'yellow', // Yellow 3 => 'green', // Green 4 => 'blue', // Blue 5 => 'magenta', // Pink 6 => 'magenta', // Purple 7 => 'default', // Checkered ); private static $colorSpec = array( 'red' => 0, 'r' => 0, 0 => 0, 'orange' => 1, 'o' => 1, 1 => 1, 'yellow' => 2, 'y' => 2, 2 => 2, 'green' => 3, 'g' => 3, 3 => 3, 'blue' => 4, 'b' => 4, 4 => 4, 'pink' => 5, 'p' => 5, 5 => 5, 'purple' => 6, 'v' => 6, 6 => 6, 'checkered' => 7, 'c' => 7, 7 => 7, ); public function getWorkflowName() { return 'flag'; } public function getCommandSynopses() { return phutil_console_format(<< 'objects', 'clear' => array( 'help' => 'Delete the flag on an object.' ), 'edit' => array( 'help' => 'Edit the flag on an object.' ), 'color' => array( 'param' => 'color', 'help' => 'Set the color of a flag.' ), 'note' => array( 'param' => 'note', 'help' => 'Set the note on a flag.' ), ); } public function requiresConduit() { return true; } public function requiresAuthentication() { return true; } private static function flagWasEdited($flag, $verb) { $color = idx(self::$colorMap, $flag['color'], 'cyan'); $note = $flag['note']; if ($note) { // Make sure notes that are long or have line breaks in them or // whatever don't mess up the formatting. $note = implode(' ', preg_split('/\s+/', $note)); $note = ' ('.phutil_utf8_shorten($note, 40, '...').')'; } echo phutil_console_format( "%s flag%s $verb!\n", $flag['colorName'], $note); } public function run() { $conduit = $this->getConduit(); $objects = $this->getArgument('objects', array()); $phids = array(); $clear = $this->getArgument('clear'); $edit = $this->getArgument('edit'); // I don't trust PHP to distinguish 0 (red) from null. $color = $this->getArgument('color', -1); $note = $this->getArgument('note'); $editing = $edit || ($color != -1) || $note; if ($editing && $clear) { throw new ArcanistUsageException("You can't both edit and clear a flag."); } if (($editing || $clear) && count($objects) != 1) { throw new ArcanistUsageException("Specify exactly one object."); } if (!empty($objects)) { // First off, convert the passed objects to PHIDs. $handles = $conduit->callMethodSynchronous( 'phid.lookup', array( 'names' => $objects, )); foreach ($objects as $object) { if (isset($handles[$object])) { $phids[$object] = $handles[$object]['phid']; } else { echo phutil_console_format("**%s** doesn't exist.\n", $object); } } if (empty($phids)) { // flag.query treats an empty objectPHIDs parameter as "don't use this // constraint". However, if the user gives a list of objects but none // of them exist and have flags, we shouldn't dump the full list on // them after telling them that. Conveniently, we already told them, // so we can go quit now. return 0; } } if ($clear) { // All right, we're going to clear a flag. First clear it. Then tell the // user we cleared it. Step four: profit! $flag = $conduit->callMethodSynchronous( 'flag.delete', array( 'objectPHID' => head($phids), )); if (!$flag) { echo phutil_console_format("**%s** has no flag to clear.\n", $object); } else { self::flagWasEdited($flag, 'deleted'); } } elseif ($editing) { // Let's set some flags. Just like Minesweeper, but less distracting. $flag_params = array( 'objectPHID' => head($phids), ); if (isset(self::$colorSpec[$color])) { $flag_params['color'] = self::$colorSpec[strtolower($color)]; } if ($note) { $flag_params['note'] = $note; } $flag = $conduit->callMethodSynchronous( 'flag.edit', $flag_params ); self::flagWasEdited($flag, $flag['new'] ? 'created' : 'edited'); } else { // Okay, list mode. Let's find the flags, which we didn't need to do // otherwise because Conduit does it for us. $flags = ipull( $this->getConduit()->callMethodSynchronous( 'flag.query', array( 'ownerPHIDs' => array($this->getUserPHID()), 'objectPHIDs' => array_values($phids), )), null, 'objectPHID'); foreach ($phids as $object => $phid) { if (!isset($flags[$phid])) { echo phutil_console_format("**%s** has no flag.\n", $object); } } if (empty($flags)) { // If the user passed no object names, then we should print the full // list, but it's empty, so tell the user they have no flags. // If the user passed object names, we already told them all their // objects are nonexistent or unflagged. if (empty($objects)) { echo "You have no flagged objects.\n"; } } else { // Print ALL the flags. With fancy formatting. Because fancy formatting // is _cool_. $name_len = 1 + max(array_map('strlen', ipull($flags, 'colorName'))); foreach ($flags as $flag) { $color = idx(self::$colorMap, $flag['color'], 'cyan'); echo phutil_console_format( "[%s] %s\n", str_pad($flag['colorName'], $name_len), $flag['handle']['fullname']); if ($flag['note']) { $note = phutil_console_wrap($flag['note'], $name_len + 3); echo rtrim($note)."\n"; } } } } } }