mirror of https://github.com/halo-dev/halo
feat: support theme require halo version. (#544)
* feat: support theme require halo version. * fix: com.sun.xml.internal.ws.util does not exist error. * fix: com.sun.xml.internal.ws.util does not exist error again. * Update ThemeServiceImpl.javapull/550/head
parent
bb8ee0f074
commit
08c579a095
|
@ -0,0 +1,18 @@
|
||||||
|
package run.halo.app.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme not support exception.
|
||||||
|
*
|
||||||
|
* @author ryanwang
|
||||||
|
* @date 2020-02-03
|
||||||
|
*/
|
||||||
|
public class ThemeNotSupportException extends BadRequestException {
|
||||||
|
|
||||||
|
public ThemeNotSupportException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ThemeNotSupportException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -54,6 +54,11 @@ public class ThemeProperty {
|
||||||
*/
|
*/
|
||||||
private String version;
|
private String version;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Require halo version.
|
||||||
|
*/
|
||||||
|
private String require;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Theme author.
|
* Theme author.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,8 +4,13 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.jgit.api.Git;
|
import org.eclipse.jgit.api.Git;
|
||||||
import org.eclipse.jgit.api.PullResult;
|
import org.eclipse.jgit.api.PullResult;
|
||||||
|
import org.eclipse.jgit.api.ResetCommand;
|
||||||
import org.eclipse.jgit.api.errors.GitAPIException;
|
import org.eclipse.jgit.api.errors.GitAPIException;
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
|
import org.eclipse.jgit.lib.Repository;
|
||||||
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
import org.eclipse.jgit.revwalk.RevWalk;
|
||||||
import org.eclipse.jgit.transport.RemoteConfig;
|
import org.eclipse.jgit.transport.RemoteConfig;
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
|
@ -31,10 +36,7 @@ import run.halo.app.model.support.HaloConst;
|
||||||
import run.halo.app.model.support.ThemeFile;
|
import run.halo.app.model.support.ThemeFile;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.ThemeService;
|
import run.halo.app.service.ThemeService;
|
||||||
import run.halo.app.utils.FileUtils;
|
import run.halo.app.utils.*;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
|
||||||
import run.halo.app.utils.GitUtils;
|
|
||||||
import run.halo.app.utils.HaloUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
@ -477,6 +479,11 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
throw new AlreadyExistsException("当前安装的主题已存在");
|
throw new AlreadyExistsException("当前安装的主题已存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not support current halo version.
|
||||||
|
if (StringUtils.isNotEmpty(tmpThemeProperty.getRequire()) && !VersionUtil.compareVersion(HaloConst.HALO_VERSION, tmpThemeProperty.getRequire())) {
|
||||||
|
throw new ThemeNotSupportException("当前主题仅支持 Halo " + tmpThemeProperty.getRequire() + " 以上的版本");
|
||||||
|
}
|
||||||
|
|
||||||
// Copy the temporary path to current theme folder
|
// Copy the temporary path to current theme folder
|
||||||
Path targetThemePath = themeWorkDir.resolve(tmpThemeProperty.getId());
|
Path targetThemePath = themeWorkDir.resolve(tmpThemeProperty.getId());
|
||||||
FileUtils.copyFolder(themeTmpPath, targetThemePath);
|
FileUtils.copyFolder(themeTmpPath, targetThemePath);
|
||||||
|
@ -533,6 +540,9 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
try {
|
try {
|
||||||
pullFromGit(updatingTheme);
|
pullFromGit(updatingTheme);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
if (e instanceof ThemeNotSupportException) {
|
||||||
|
throw (ThemeNotSupportException) e;
|
||||||
|
}
|
||||||
throw new ThemeUpdateException("主题更新失败!您与主题作者可能同时更改了同一个文件,您也可以尝试删除主题并重新拉取最新的主题", e).setErrorData(themeId);
|
throw new ThemeUpdateException("主题更新失败!您与主题作者可能同时更改了同一个文件,您也可以尝试删除主题并重新拉取最新的主题", e).setErrorData(themeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,6 +589,11 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
throw new ServiceException("上传的主题包不是该主题的更新包: " + file.getOriginalFilename());
|
throw new ServiceException("上传的主题包不是该主题的更新包: " + file.getOriginalFilename());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not support current halo version.
|
||||||
|
if (StringUtils.isNotEmpty(prepareThemeProperty.getRequire()) && !VersionUtil.compareVersion(HaloConst.HALO_VERSION, prepareThemeProperty.getRequire())) {
|
||||||
|
throw new ThemeNotSupportException("新版本主题仅支持 Halo " + prepareThemeProperty.getRequire() + " 以上的版本");
|
||||||
|
}
|
||||||
|
|
||||||
// Coping new theme files to old theme folder.
|
// Coping new theme files to old theme folder.
|
||||||
FileUtils.copyFolder(preparePath, Paths.get(updatingTheme.getThemePath()));
|
FileUtils.copyFolder(preparePath, Paths.get(updatingTheme.getThemePath()));
|
||||||
|
|
||||||
|
@ -605,6 +620,15 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
git = GitUtils.openOrInit(Paths.get(themeProperty.getThemePath()));
|
git = GitUtils.openOrInit(Paths.get(themeProperty.getThemePath()));
|
||||||
|
|
||||||
|
Repository repository = git.getRepository();
|
||||||
|
|
||||||
|
RevWalk revWalk = new RevWalk(repository);
|
||||||
|
|
||||||
|
Ref ref = repository.getAllRefs().get(Constants.HEAD);
|
||||||
|
|
||||||
|
RevCommit lastCommit = revWalk.parseCommit(ref.getObjectId());
|
||||||
|
|
||||||
// Force to set remote name
|
// Force to set remote name
|
||||||
git.remoteRemove().setRemoteName(THEME_PROVIDER_REMOTE_NAME).call();
|
git.remoteRemove().setRemoteName(THEME_PROVIDER_REMOTE_NAME).call();
|
||||||
RemoteConfig remoteConfig = git.remoteAdd()
|
RemoteConfig remoteConfig = git.remoteAdd()
|
||||||
|
@ -647,6 +671,19 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
|
|
||||||
throw new ThemeUpdateException("拉取失败!您与主题作者可能同时更改了同一个文件");
|
throw new ThemeUpdateException("拉取失败!您与主题作者可能同时更改了同一个文件");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// updated successfully.
|
||||||
|
ThemeProperty updatedThemeProperty = getProperty(Paths.get(themeProperty.getThemePath()));
|
||||||
|
|
||||||
|
// Not support current halo version.
|
||||||
|
if (StringUtils.isNotEmpty(updatedThemeProperty.getRequire()) && !VersionUtil.compareVersion(HaloConst.HALO_VERSION, updatedThemeProperty.getRequire())) {
|
||||||
|
// reset theme version
|
||||||
|
git.reset()
|
||||||
|
.setMode(ResetCommand.ResetType.HARD)
|
||||||
|
.setRef(lastCommit.getName())
|
||||||
|
.call();
|
||||||
|
throw new ThemeNotSupportException("新版本主题仅支持 Halo " + updatedThemeProperty.getRequire() + " 以上的版本");
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
GitUtils.closeQuietly(git);
|
GitUtils.closeQuietly(git);
|
||||||
}
|
}
|
||||||
|
@ -826,7 +863,7 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
// Set screenshots
|
// Set screenshots
|
||||||
getScreenshotsFileName(themePath).ifPresent(screenshotsName ->
|
getScreenshotsFileName(themePath).ifPresent(screenshotsName ->
|
||||||
themeProperty.setScreenshots(StringUtils.join(optionService.getBlogBaseUrl(),
|
themeProperty.setScreenshots(StringUtils.join(optionService.getBlogBaseUrl(),
|
||||||
"/",
|
"/themes/",
|
||||||
FilenameUtils.getBasename(themeProperty.getThemePath()),
|
FilenameUtils.getBasename(themeProperty.getThemePath()),
|
||||||
"/",
|
"/",
|
||||||
screenshotsName)));
|
screenshotsName)));
|
||||||
|
|
|
@ -17,7 +17,7 @@ import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
|
||||||
*
|
*
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @date 2017/12/22
|
* @date 2017-12-22
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HaloUtils {
|
public class HaloUtils {
|
||||||
|
@ -232,22 +232,6 @@ public class HaloUtils {
|
||||||
return String.valueOf(System.currentTimeMillis());
|
return String.valueOf(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalize url.
|
|
||||||
*
|
|
||||||
* @param url url must not be blank
|
|
||||||
* @return normalized url
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
public static String normalizeUrl(@NonNull String url) {
|
|
||||||
Assert.hasText(url, "Url must not be blank");
|
|
||||||
|
|
||||||
StringUtils.removeEnd(url, "html");
|
|
||||||
StringUtils.removeEnd(url, "htm");
|
|
||||||
|
|
||||||
return SlugUtils.slugify(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets machine IP address.
|
* Gets machine IP address.
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
package run.halo.app.utils;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
|
import java.util.StringTokenizer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ryanwang
|
||||||
|
* @date 2020-02-03
|
||||||
|
* @see com.sun.xml.internal.ws.util.VersionUtil
|
||||||
|
*/
|
||||||
|
public class VersionUtil {
|
||||||
|
|
||||||
|
public VersionUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int[] getCanonicalVersion(String version) {
|
||||||
|
int[] canonicalVersion = new int[]{1, 1, 0, 0};
|
||||||
|
StringTokenizer tokenizer = new StringTokenizer(version, ".");
|
||||||
|
String token = tokenizer.nextToken();
|
||||||
|
canonicalVersion[0] = Integer.parseInt(token);
|
||||||
|
token = tokenizer.nextToken();
|
||||||
|
StringTokenizer subTokenizer;
|
||||||
|
if (!token.contains(StrUtil.UNDERLINE)) {
|
||||||
|
canonicalVersion[1] = Integer.parseInt(token);
|
||||||
|
} else {
|
||||||
|
subTokenizer = new StringTokenizer(token, "_");
|
||||||
|
canonicalVersion[1] = Integer.parseInt(subTokenizer.nextToken());
|
||||||
|
canonicalVersion[3] = Integer.parseInt(subTokenizer.nextToken());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tokenizer.hasMoreTokens()) {
|
||||||
|
token = tokenizer.nextToken();
|
||||||
|
if (!token.contains(StrUtil.UNDERLINE)) {
|
||||||
|
canonicalVersion[2] = Integer.parseInt(token);
|
||||||
|
if (tokenizer.hasMoreTokens()) {
|
||||||
|
canonicalVersion[3] = Integer.parseInt(tokenizer.nextToken());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
subTokenizer = new StringTokenizer(token, "_");
|
||||||
|
canonicalVersion[2] = Integer.parseInt(subTokenizer.nextToken());
|
||||||
|
canonicalVersion[3] = Integer.parseInt(subTokenizer.nextToken());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canonicalVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int compare(String version1, String version2) {
|
||||||
|
int[] canonicalVersion1 = getCanonicalVersion(version1);
|
||||||
|
int[] canonicalVersion2 = getCanonicalVersion(version2);
|
||||||
|
if (canonicalVersion1[0] < canonicalVersion2[0]) {
|
||||||
|
return -1;
|
||||||
|
} else if (canonicalVersion1[0] > canonicalVersion2[0]) {
|
||||||
|
return 1;
|
||||||
|
} else if (canonicalVersion1[1] < canonicalVersion2[1]) {
|
||||||
|
return -1;
|
||||||
|
} else if (canonicalVersion1[1] > canonicalVersion2[1]) {
|
||||||
|
return 1;
|
||||||
|
} else if (canonicalVersion1[2] < canonicalVersion2[2]) {
|
||||||
|
return -1;
|
||||||
|
} else if (canonicalVersion1[2] > canonicalVersion2[2]) {
|
||||||
|
return 1;
|
||||||
|
} else if (canonicalVersion1[3] < canonicalVersion2[3]) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return canonicalVersion1[3] > canonicalVersion2[3] ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compare version.
|
||||||
|
*
|
||||||
|
* @param current current version.
|
||||||
|
* @param require require version.
|
||||||
|
* @return true or false.
|
||||||
|
*/
|
||||||
|
public static boolean compareVersion(String current, String require) {
|
||||||
|
return compare(current, require) >= 0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package run.halo.app.utils;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.RandomUtils;
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
@ -15,7 +14,8 @@ import static org.junit.Assert.assertThat;
|
||||||
* Halo utilities test.
|
* Halo utilities test.
|
||||||
*
|
*
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @date 3/29/19
|
* @author ryanwang
|
||||||
|
* @date 2019-03-29
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HaloUtilsTest {
|
public class HaloUtilsTest {
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
package run.halo.app.utils;
|
||||||
|
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ryanwang
|
||||||
|
* @date 2020-02-03
|
||||||
|
*/
|
||||||
|
public class VersionUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void compareVersion() {
|
||||||
|
Assert.assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1"));
|
||||||
|
|
||||||
|
Assert.assertTrue(VersionUtil.compareVersion("1.2.1", "1.2.0"));
|
||||||
|
|
||||||
|
Assert.assertTrue(VersionUtil.compareVersion("1.2.0", "1.1.1.0"));
|
||||||
|
|
||||||
|
Assert.assertTrue(VersionUtil.compareVersion("1.2.0", "0.4.4"));
|
||||||
|
|
||||||
|
Assert.assertFalse(VersionUtil.compareVersion("1.1.1", "1.2.0"));
|
||||||
|
|
||||||
|
Assert.assertFalse(VersionUtil.compareVersion("0.0.1", "1.2.0"));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue