diff --git a/README.md b/README.md index afec2b7..f3aadd8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ For quick run you need: * After unpacking archive you can run server executing: ```bash - java -jar build/deploy/git-lfs-migrate.jar -s source-repo.git -d target-repo.git -l http://test:test@lfs-server/ .psd .zip .bin + java -jar build/deploy/git-lfs-migrate.jar -s source-repo.git -d target-repo.git -l http://test:test@lfs-server/ "*.psd" "*.zip" "*.bin" ``` For example, you can convert bozaro/git-lfs-migrate to bozaro/git-lfs-migrate-converted by commands: @@ -27,7 +27,7 @@ git clone --mirror git@github.com:bozaro/git-lfs-migrate.git # Convert repository with moving .md and .jar file to LFS # -# Usage:
[options] LFS file suffixes +# Usage:
[options] LFS file glob patterns # Options: # -c, --cache # Source repository @@ -56,8 +56,8 @@ java -jar git-lfs-migrate.jar \ -s git-lfs-migrate.git \ -d git-lfs-migrate-converted.git \ -g git@github.com:bozaro/git-lfs-migrate-converted.git \ - .md \ - .jar + "*.md" \ + "*.jar" # Push coverted repository to new repository cd git-lfs-migrate-converted.git @@ -101,5 +101,5 @@ call gradlew.bat deployZip When build completes you can convert repository executing: ```bash -java -jar build/deploy/git-lfs-migrate.jar -s source-repo.git -d target-repo.git -l http://test:test@lfs-server/ .psd .zip .bin +java -jar build/deploy/git-lfs-migrate.jar -s source-repo.git -d target-repo.git -l http://test:test@lfs-server/ "*.psd" "*.zip" "*.bin" ``` diff --git a/src/main/java/git/lfs/migrate/GitConverter.java b/src/main/java/git/lfs/migrate/GitConverter.java index 3c21cce..917f1ba 100644 --- a/src/main/java/git/lfs/migrate/GitConverter.java +++ b/src/main/java/git/lfs/migrate/GitConverter.java @@ -1,6 +1,8 @@ package git.lfs.migrate; import org.apache.commons.codec.binary.Hex; +import org.eclipse.jgit.errors.InvalidPatternException; +import org.eclipse.jgit.fnmatch.FileNameMatcher; import org.eclipse.jgit.lib.*; import org.eclipse.jgit.revwalk.*; import org.eclipse.jgit.treewalk.CanonicalTreeParser; @@ -31,7 +33,7 @@ public class GitConverter implements AutoCloseable { @NotNull private static final String GIT_ATTRIBUTES = ".gitattributes"; @NotNull - private final String[] suffixes; + private final String[] globs; @NotNull private final File basePath; @NotNull @@ -41,9 +43,14 @@ public class GitConverter implements AutoCloseable { @NotNull private final HTreeMap cacheSha256; - public GitConverter(@NotNull File cachePath, @NotNull File basePath, @NotNull String[] suffixes) throws IOException { + public GitConverter(@NotNull File cachePath, @NotNull File basePath, @NotNull String[] globs) throws IOException, InvalidPatternException { this.basePath = basePath; - this.suffixes = suffixes.clone(); + this.globs = globs.clone(); + Arrays.sort(globs); + + for (String glob : globs) { + new FileNameMatcher(glob, '/'); + } tempPath = new File(basePath, "lfs/tmp"); makeParentDirs(tempPath); @@ -182,7 +189,7 @@ private List getEntries() throws IOException { blobTask = TaskType.Attribute; pathTask = null; needAttributes = false; - } else if (isFile(fileMode) && matchFilename(treeParser.getEntryPathString())) { + } else if (isFile(fileMode) && matchFilename(path + "/" + treeParser.getEntryPathString())) { blobTask = TaskType.UploadLfs; pathTask = null; } else { @@ -192,7 +199,7 @@ private List getEntries() throws IOException { entries.add(new GitTreeEntry(fileMode, new TaskKey(blobTask, pathTask, treeParser.getEntryObjectId()), treeParser.getEntryPathString())); treeParser.next(); } - if (needAttributes && suffixes.length > 0) { + if (needAttributes && globs.length > 0) { entries.add(new GitTreeEntry(FileMode.REGULAR_FILE, new TaskKey(TaskType.Attribute, null, ObjectId.zeroId()), GIT_ATTRIBUTES)); } return entries; @@ -225,12 +232,21 @@ public ObjectId convert(@NotNull ObjectInserter inserter, @NotNull ConvertResolv } private boolean matchFilename(@NotNull String fileName) { - for (String suffix : suffixes) { - if (fileName.endsWith(suffix)) { - return true; + if (!fileName.startsWith("/")) { + throw new IllegalStateException("Unexpected file name: " + fileName); + } + try { + for (String glob : globs) { + final FileNameMatcher matcher = new FileNameMatcher(glob, null); + matcher.append(fileName.substring(1)); + if (matcher.isMatch()) { + return true; + } } + return false; + } catch (InvalidPatternException e) { + throw new IllegalArgumentException(e); } - return false; } @NotNull @@ -355,8 +371,8 @@ public Iterable depends() throws IOException { @Override public ObjectId convert(@NotNull ObjectInserter inserter, @NotNull ConvertResolver resolver, @Nullable Uploader uploader) throws IOException { final Set attributes = new TreeSet<>(); - for (String suffix : suffixes) { - attributes.add("*" + suffix + "\tfilter=lfs diff=lfs merge=lfs -crlf"); + for (String glob : globs) { + attributes.add(glob + "\tfilter=lfs diff=lfs merge=lfs -crlf"); } final ByteArrayOutputStream blob = new ByteArrayOutputStream(); try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(openAttributes(reader, id), StandardCharsets.UTF_8))) { diff --git a/src/main/java/git/lfs/migrate/Main.java b/src/main/java/git/lfs/migrate/Main.java index 72c07c9..ed6e224 100644 --- a/src/main/java/git/lfs/migrate/Main.java +++ b/src/main/java/git/lfs/migrate/Main.java @@ -3,6 +3,7 @@ import com.beust.jcommander.JCommander; import com.beust.jcommander.Parameter; import org.apache.commons.httpclient.HttpStatus; +import org.eclipse.jgit.errors.InvalidPatternException; import org.eclipse.jgit.lib.*; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.jetbrains.annotations.NotNull; @@ -43,7 +44,7 @@ public class Main { @NotNull private static final Logger log = LoggerFactory.getLogger(Main.class); - public static void main(@NotNull String[] args) throws IOException, InterruptedException, ExecutionException { + public static void main(@NotNull String[] args) throws IOException, InterruptedException, ExecutionException, InvalidPatternException { final CmdArgs cmd = new CmdArgs(); final JCommander jc = new JCommander(cmd); jc.parse(args); @@ -69,7 +70,7 @@ public static void main(@NotNull String[] args) throws IOException, InterruptedE } return; } - processRepository(cmd.src, cmd.dst, cmd.cache, auth, cmd.writeThreads, cmd.uploadThreads, cmd.suffixes.toArray(new String[cmd.suffixes.size()])); + processRepository(cmd.src, cmd.dst, cmd.cache, auth, cmd.writeThreads, cmd.uploadThreads, cmd.globs.toArray(new String[cmd.globs.size()])); log.info("Convert time: {}", System.currentTimeMillis() - time); } @@ -112,7 +113,7 @@ private static boolean checkLfsAuthenticate(@Nullable AuthProvider auth) throws return false; } - public static void processRepository(@NotNull File srcPath, @NotNull File dstPath, @NotNull File cachePath, @Nullable AuthProvider auth, int writeThreads, int uploadThreads, @NotNull String... suffixes) throws IOException, InterruptedException, ExecutionException { + public static void processRepository(@NotNull File srcPath, @NotNull File dstPath, @NotNull File cachePath, @Nullable AuthProvider auth, int writeThreads, int uploadThreads, @NotNull String... globs) throws IOException, InterruptedException, ExecutionException, InvalidPatternException { removeDirectory(dstPath); dstPath.mkdirs(); @@ -123,7 +124,7 @@ public static void processRepository(@NotNull File srcPath, @NotNull File dstPat .setMustExist(false) .setGitDir(dstPath).build(); - final GitConverter converter = new GitConverter(cachePath, dstPath, suffixes); + final GitConverter converter = new GitConverter(cachePath, dstPath, globs); try { dstRepo.create(true); // Load all revision list. @@ -420,9 +421,9 @@ public static class CmdArgs { @Parameter(names = {"--check-lfs"}, description = "Check LFS server settings and exit") private boolean checkLfs = false; - @Parameter(description = "LFS file suffixes") + @Parameter(description = "LFS file glob patterns") @NotNull - private List suffixes = new ArrayList<>(); + private List globs = new ArrayList<>(); @Parameter(names = {"-h", "--help"}, description = "Show help", help = true) private boolean help = false; }