@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make Diffusion do an alright job on Git LFS objects

Summary: Ref T7789. This isn't the most perfect UI imaginable, but it's similar to what GitHub does and seems reasonable.

Test Plan:
{F1180271}

{F1180272}

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T7789

Differential Revision: https://secure.phabricator.com/D15494

+125 -2
+125 -2
src/applications/diffusion/controller/DiffusionBrowseController.php
··· 192 192 } 193 193 194 194 $data = $file->loadFileData(); 195 - if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) { 195 + 196 + $ref = $this->getGitLFSRef($repository, $data); 197 + if ($ref) { 198 + if ($view == 'git-lfs') { 199 + $file = $this->loadGitLFSFile($ref); 200 + 201 + // Rename the file locally so we generate a better vanity URI for 202 + // it. In storage, it just has a name like "lfs-13f9a94c0923...", 203 + // since we don't get any hints about possible human-readable names 204 + // at upload time. 205 + $basename = basename($drequest->getPath()); 206 + $file->makeEphemeral(); 207 + $file->setName($basename); 208 + 209 + return $file->getRedirectResponse(); 210 + } else { 211 + $corpus = $this->buildGitLFSCorpus($ref); 212 + } 213 + } else if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) { 196 214 $file_uri = $file->getBestURI(); 197 215 198 216 if ($file->isViewableImage()) { ··· 930 948 return $button; 931 949 } 932 950 933 - private function renderFileButton($file_uri = null) { 951 + private function renderFileButton($file_uri = null, $label = null) { 934 952 935 953 $base_uri = $this->getRequest()->getRequestURI(); 936 954 ··· 942 960 $text = pht('View Raw File'); 943 961 $href = $base_uri->alter('view', 'raw'); 944 962 $icon = 'fa-file-text'; 963 + } 964 + 965 + if ($label !== null) { 966 + $text = $label; 945 967 } 946 968 947 969 $button = id(new PHUIButtonView()) ··· 953 975 return $button; 954 976 } 955 977 978 + private function renderGitLFSButton() { 979 + $viewer = $this->getViewer(); 980 + 981 + $uri = $this->getRequest()->getRequestURI(); 982 + $href = $uri->alter('view', 'git-lfs'); 983 + 984 + $text = pht('Download from Git LFS'); 985 + $icon = 'fa-download'; 986 + 987 + return id(new PHUIButtonView()) 988 + ->setTag('a') 989 + ->setText($text) 990 + ->setHref($href) 991 + ->setIcon($icon); 992 + } 956 993 957 994 private function buildDisplayRows( 958 995 array $lines, ··· 1888 1925 ), 1889 1926 $corpus); 1890 1927 } 1928 + 1929 + private function getGitLFSRef(PhabricatorRepository $repository, $data) { 1930 + if (!$repository->canUseGitLFS()) { 1931 + return null; 1932 + } 1933 + 1934 + $lfs_pattern = '(^version https://git-lfs\\.github\\.com/spec/v1[\r\n])'; 1935 + if (!preg_match($lfs_pattern, $data)) { 1936 + return null; 1937 + } 1938 + 1939 + $matches = null; 1940 + if (!preg_match('(^oid sha256:(.*)$)m', $data, $matches)) { 1941 + return null; 1942 + } 1943 + 1944 + $hash = $matches[1]; 1945 + $hash = trim($hash); 1946 + 1947 + return id(new PhabricatorRepositoryGitLFSRefQuery()) 1948 + ->setViewer($this->getViewer()) 1949 + ->withRepositoryPHIDs(array($repository->getPHID())) 1950 + ->withObjectHashes(array($hash)) 1951 + ->executeOne(); 1952 + } 1953 + 1954 + private function buildGitLFSCorpus(PhabricatorRepositoryGitLFSRef $ref) { 1955 + // TODO: We should probably test if we can load the file PHID here and 1956 + // show the user an error if we can't, rather than making them click 1957 + // through to hit an error. 1958 + 1959 + $header = id(new PHUIHeaderView()) 1960 + ->setHeader(basename($this->getDiffusionRequest()->getPath())) 1961 + ->setHeaderIcon('fa-archive'); 1962 + 1963 + $severity = PHUIInfoView::SEVERITY_NOTICE; 1964 + 1965 + $messages = array(); 1966 + $messages[] = pht( 1967 + 'This %s file is stored in Git Large File Storage.', 1968 + phutil_format_bytes($ref->getByteSize())); 1969 + 1970 + try { 1971 + $file = $this->loadGitLFSFile($ref); 1972 + $data = $this->renderGitLFSButton(); 1973 + $header->addActionLink($data); 1974 + } catch (Exception $ex) { 1975 + $severity = PHUIInfoView::SEVERITY_ERROR; 1976 + $messages[] = pht('The data for this file could not be loaded.'); 1977 + } 1978 + 1979 + $raw = $this->renderFileButton(null, pht('View Raw LFS Pointer')); 1980 + $header->addActionLink($raw); 1981 + 1982 + $corpus = id(new PHUIObjectBoxView()) 1983 + ->setHeader($header) 1984 + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) 1985 + ->setCollapsed(true); 1986 + 1987 + if ($messages) { 1988 + $corpus->setInfoView( 1989 + id(new PHUIInfoView()) 1990 + ->setSeverity($severity) 1991 + ->setErrors($messages)); 1992 + } 1993 + 1994 + return $corpus; 1995 + } 1996 + 1997 + private function loadGitLFSFile(PhabricatorRepositoryGitLFSRef $ref) { 1998 + $viewer = $this->getViewer(); 1999 + 2000 + $file = id(new PhabricatorFileQuery()) 2001 + ->setViewer($viewer) 2002 + ->withPHIDs(array($ref->getFilePHID())) 2003 + ->executeOne(); 2004 + if (!$file) { 2005 + throw new Exception( 2006 + pht( 2007 + 'Failed to load file object for Git LFS ref "%s"!', 2008 + $ref->getObjectHash())); 2009 + } 2010 + 2011 + return $file; 2012 + } 2013 + 1891 2014 1892 2015 }