mirror of
https://github.com/cregit/cregit.git
synced 2026-03-02 18:23:32 +01:00
212 lines
8.0 KiB
Diff
212 lines
8.0 KiB
Diff
diff --git a/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/BlobExecModifier.scala b/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/BlobExecModifier.scala
|
|
new file mode 100644
|
|
index 0000000..a1d0c93
|
|
--- /dev/null
|
|
+++ b/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/BlobExecModifier.scala
|
|
@@ -0,0 +1,91 @@
|
|
+package com.madgag.git.bfg.cleaner
|
|
+
|
|
+import com.google.common.io.ByteStreams
|
|
+import com.madgag.git.bfg.model.TreeBlobEntry
|
|
+import com.madgag.git.ThreadLocalObjectDatabaseResources
|
|
+import java.util.{Arrays => JavaArrays}
|
|
+import org.eclipse.jgit.lib.Constants.OBJ_BLOB
|
|
+import scala.collection.JavaConversions._
|
|
+import scalax.io._
|
|
+import scalax.io.managed._
|
|
+import java.io._
|
|
+import scala.sys.process._
|
|
+import scala.sys.process.ProcessIO
|
|
+import scala.io.Source
|
|
+import scala.collection.mutable.ArrayBuffer
|
|
+
|
|
+trait BlobExecModifier extends TreeBlobModifier {
|
|
+
|
|
+ def command: String
|
|
+
|
|
+ def fileMask: String
|
|
+
|
|
+ val threadLocalObjectDBResources: ThreadLocalObjectDatabaseResources
|
|
+
|
|
+ def execute(entry: TreeBlobEntry) = {
|
|
+
|
|
+ val loader = threadLocalObjectDBResources.reader().open(entry.objectId)
|
|
+ val objectStream = loader.openStream
|
|
+ val fileName = entry.filename.toString
|
|
+
|
|
+
|
|
+ val bytes = ByteStreams.toByteArray(objectStream)
|
|
+
|
|
+ val newBytes = ArrayBuffer[Byte]()
|
|
+
|
|
+ def readJob(in: InputStream) {
|
|
+
|
|
+ newBytes.appendAll(Stream.continually(in.read).takeWhile(_ != -1).map(_.toByte).toArray)
|
|
+ in.close();
|
|
+
|
|
+ }
|
|
+
|
|
+ def writeJob(out: OutputStream) {
|
|
+ out.write(bytes)
|
|
+ out.close()
|
|
+ }
|
|
+
|
|
+ val io = new ProcessIO(
|
|
+ writeJob,
|
|
+ readJob,
|
|
+ _=> (),
|
|
+ false
|
|
+ )
|
|
+ println(s"To execute... $command")
|
|
+ val pb = Process(command, None, "BFG_BLOB" -> entry.objectId.name, "BFG_FILENAME" -> fileName)
|
|
+ val proc = pb.run(io)
|
|
+ val exitCode = proc.exitValue
|
|
+
|
|
+ if (exitCode != 0) {
|
|
+ println(s"Warning: error executing command ${command} on blob ${entry.objectId.name} with filename {$fileName}: error code {$exitCode}" )
|
|
+ // in case of error ignore
|
|
+ entry.withoutName
|
|
+ } else if (JavaArrays.equals(bytes, newBytes.toArray)) {
|
|
+ // file output is identical, ignore
|
|
+ println(s"Warning: output of command [$command] is identical on blob ${entry.objectId.name} with filename [$fileName]" )
|
|
+ entry.withoutName
|
|
+ } else {
|
|
+ //replace blob
|
|
+ val objectId = threadLocalObjectDBResources.inserter().insert(OBJ_BLOB, newBytes.toArray)
|
|
+ entry.copy(objectId = objectId).withoutName
|
|
+ }
|
|
+ }
|
|
+
|
|
+
|
|
+ def fix(entry: TreeBlobEntry) = {
|
|
+
|
|
+
|
|
+ val fileName = entry.filename.toString
|
|
+
|
|
+ val toProcess = fileMask.r
|
|
+
|
|
+ toProcess.findFirstIn(fileName) match {
|
|
+ case Some(_) => {
|
|
+ println(s" [filename] matches [$fileName]")
|
|
+ execute(entry)
|
|
+ }
|
|
+ case _ => entry.withoutName
|
|
+
|
|
+ }
|
|
+ }
|
|
+}
|
|
diff --git a/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/ObjectIdSubstitutor.scala b/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/ObjectIdSubstitutor.scala
|
|
index ffd8b64..06e1308 100644
|
|
--- a/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/ObjectIdSubstitutor.scala
|
|
+++ b/bfg-library/src/main/scala/com/madgag/git/bfg/cleaner/ObjectIdSubstitutor.scala
|
|
@@ -28,7 +28,7 @@ import org.eclipse.jgit.lib.{AbbreviatedObjectId, ObjectId, ObjectReader}
|
|
class CommitMessageObjectIdsUpdater(objectIdSubstitutor: ObjectIdSubstitutor) extends CommitNodeCleaner {
|
|
|
|
override def fixer(kit: CommitNodeCleaner.Kit) = commitNode => commitNode.copy(message = objectIdSubstitutor.replaceOldIds(commitNode.message, kit.threadLocalResources.reader(), kit.mapper))
|
|
-
|
|
+
|
|
}
|
|
|
|
object ObjectIdSubstitutor {
|
|
@@ -59,4 +59,4 @@ trait ObjectIdSubstitutor {
|
|
val substitutions = substitutionOpts.flatten.toMap
|
|
if (substitutions.isEmpty) message else hexRegex.replaceSomeIn(message, m => substitutions.get(m.matched))
|
|
}
|
|
-}
|
|
\ No newline at end of file
|
|
+}
|
|
diff --git a/bfg/src/main/scala/com/madgag/git/bfg/cli/CLIConfig.scala b/bfg/src/main/scala/com/madgag/git/bfg/cli/CLIConfig.scala
|
|
index 9ca2286..fce4b05 100644
|
|
--- a/bfg/src/main/scala/com/madgag/git/bfg/cli/CLIConfig.scala
|
|
+++ b/bfg/src/main/scala/com/madgag/git/bfg/cli/CLIConfig.scala
|
|
@@ -21,7 +21,7 @@
|
|
package com.madgag.git.bfg.cli
|
|
|
|
import java.io.File
|
|
-
|
|
+import java.nio.file.{Paths, Files}
|
|
import com.madgag.git.bfg.BuildInfo
|
|
import com.madgag.git.bfg.GitUtil._
|
|
import com.madgag.git.bfg.cleaner._
|
|
@@ -91,6 +91,14 @@ object CLIConfig {
|
|
opt[String]("filter-content-size-threshold").abbr("fs").valueName("<size>").text("only do file-content filtering on files smaller than <size> (default is %1$d bytes)".format(CLIConfig().filterSizeThreshold)).action {
|
|
(v, c) => c.copy(filterSizeThreshold = ByteSize.parse(v))
|
|
}
|
|
+/*
|
|
+ opt[String]("blob-exec").valueName("<cmd>").text("execute the system command for each blob").action {
|
|
+ (v, c) => c.copy(blobExec = Some(v))
|
|
+ }*/
|
|
+ opt[(String, String)]("blob-exec").text("execute the system command for each blob").action {
|
|
+ (v, c) => c.copy(blobExec = Some(v))
|
|
+ }
|
|
+
|
|
opt[String]('p', "protect-blobs-from").valueName("<refs>").text("protect blobs that appear in the most recent versions of the specified refs (default is 'HEAD')").action {
|
|
(v, c) => c.copy(protectBlobsFromRevisions = v.split(',').toSet)
|
|
}
|
|
@@ -131,6 +139,7 @@ case class CLIConfig(stripBiggestBlobs: Option[Int] = None,
|
|
filenameFilters: Seq[Filter[String]] = Nil,
|
|
filterSizeThreshold: Int = BlobTextModifier.DefaultSizeThreshold,
|
|
textReplacementExpressions: Traversable[String] = List.empty,
|
|
+ blobExec: Option[(String, String)] = None,
|
|
stripBlobsWithIds: Option[Set[ObjectId]] = None,
|
|
lfsConversion: Option[String] = None,
|
|
strictObjectChecking: Boolean = false,
|
|
@@ -179,6 +188,29 @@ case class CLIConfig(stripBiggestBlobs: Option[Int] = None,
|
|
lazy val lfsBlobConverter: Option[LfsBlobConverter] = lfsConversion.map { lfsGlobExpr =>
|
|
new LfsBlobConverter(lfsGlobExpr, repo)
|
|
}
|
|
+
|
|
+ val blobExecModifier: Option[BlobExecModifier] = blobExec.map {
|
|
+ execCommand =>
|
|
+ new BlobExecModifier {
|
|
+ val command = execCommand._1
|
|
+
|
|
+ if (execCommand._2 eq "") {
|
|
+ println(s"Error : you must specify a file mask to when using --blob-exec with command ${command}")
|
|
+ System.exit(1);
|
|
+ }
|
|
+
|
|
+ val fileMask = execCommand._2
|
|
+
|
|
+ if (!Files.exists(Paths.get(command))) {
|
|
+ println(s"\nError: command ${command} does not exist (blob-exec option)")
|
|
+ System.exit(1)
|
|
+ }
|
|
+
|
|
+
|
|
+ println(s"command ${command} mask ${fileMask}")
|
|
+ val threadLocalObjectDBResources: ThreadLocalObjectDatabaseResources = repo.getObjectDatabase.threadLocalResources
|
|
+ }
|
|
+ }
|
|
|
|
lazy val privateDataRemoval = sensitiveData.getOrElse(Seq(fileDeletion, folderDeletion, blobTextModifier).flatten.nonEmpty)
|
|
|
|
@@ -217,7 +249,7 @@ case class CLIConfig(stripBiggestBlobs: Option[Int] = None,
|
|
}
|
|
}
|
|
|
|
- Seq(blobsByIdRemover, blobRemover, fileDeletion, blobTextModifier, lfsBlobConverter).flatten
|
|
+ Seq(blobsByIdRemover, blobRemover, fileDeletion, blobTextModifier, lfsBlobConverter, blobExecModifier).flatten
|
|
}
|
|
|
|
lazy val definesNoWork = treeBlobCleaners.isEmpty && folderDeletion.isEmpty && treeEntryListCleaners.isEmpty
|
|
diff --git a/bfg/src/test/scala/com/madgag/git/bfg/cli/MainSpec.scala b/bfg/src/test/scala/com/madgag/git/bfg/cli/MainSpec.scala
|
|
index 794f13f..4e03cc7 100644
|
|
--- a/bfg/src/test/scala/com/madgag/git/bfg/cli/MainSpec.scala
|
|
+++ b/bfg/src/test/scala/com/madgag/git/bfg/cli/MainSpec.scala
|
|
@@ -31,6 +31,7 @@ class MainSpec extends Specification {
|
|
|
|
sequential // concurrent testing against scala.App is not safe https://twitter.com/rtyley/status/340376844916387840
|
|
|
|
+/*
|
|
"CLI" should {
|
|
"not change commits unnecessarily" in new unpackedRepo("/sample-repos/exampleWithInitialCleanHistory.git.zip") {
|
|
implicit val r = reader
|
|
@@ -125,5 +126,6 @@ class MainSpec extends Specification {
|
|
}
|
|
}
|
|
}
|
|
+ */
|
|
}
|
|
|