source: launchers/common/src/main/scala/net/i2p/launchers/OSXDeployment.scala @ 8957c85

Last change on this file since 8957c85 was 8957c85, checked in by meeh <meeh@…>, 3 years ago

Disable debug messages.

  • Property mode set to 100644
File size: 6.9 KB
Line 
1package net.i2p.launchers
2
3import java.io.{File, IOException}
4import java.util.zip.ZipFile
5import collection.JavaConverters._
6
7/**
8  *
9  * OSXDeployment
10  *
11  * This class can be a bit new for java developers. In Scala, when inherit other classes,
12  * you would need to define their arguments if the super class only has constructors taking arguments.
13  *
14  * This child class don't take arguments, but rather get them from the signleton OSXDefaults.
15  *
16  * This class should be able to copy recursive resources into correct position for a normal deployment.
17  *
18  *
19  * This class might look like black magic for some. But what it does is to deploy a structure like for example:
20  * tree ~/Library/I2P
21  * /Users/mikalv/Library/I2P
22  * ├── blocklist.txt
23  * ├── certificates
24  * │   ├── family
25  * │   │   ├── gostcoin.crt
26  * │   │   ├── i2p-dev.crt
27  * │   │   ├── i2pd-dev.crt
28  * │   │   └── volatile.crt
29  * │   ├── i2ptunnel
30  * │   ├── news
31  * │   │   ├── ampernand_at_gmail.com.crt
32  * │   │   ├── echelon_at_mail.i2p.crt
33  * │   │   ├── str4d_at_mail.i2p.crt
34  * │   │   └── zzz_at_mail.i2p.crt
35  * │   ├── plugin
36  * │   │   ├── cacapo_at_mail.i2p.crt
37  * │   │   ├── str4d_at_mail.i2p.crt
38  * │   │   └── zzz-plugin_at_mail.i2p.crt
39  * │   ├── reseed
40  * │   │   ├── atomike_at_mail.i2p.crt
41  * │   │   ├── backup_at_mail.i2p.crt
42  * │   │   ├── bugme_at_mail.i2p.crt
43  * │   │   ├── creativecowpat_at_mail.i2p.crt
44  * │   │   ├── echelon_at_mail.i2p.crt
45  * │   │   ├── hottuna_at_mail.i2p.crt
46  * │   │   ├── igor_at_novg.net.crt
47  * │   │   ├── lazygravy_at_mail.i2p.crt
48  * │   │   ├── meeh_at_mail.i2p.crt
49  * │   │   └── zmx_at_mail.i2p.crt
50  * │   ├── revocations
51  * │   ├── router
52  * │   │   ├── echelon_at_mail.i2p.crt
53  * │   │   ├── str4d_at_mail.i2p.crt
54  * │   │   └── zzz_at_mail.i2p.crt
55  * │   └── ssl
56  * │       ├── echelon.reseed2017.crt
57  * │       ├── i2p.mooo.com.crt
58  * │       ├── i2pseed.creativecowpat.net.crt
59  * │       ├── isrgrootx1.crt
60  * │       └── reseed.onion.im.crt
61  * ├── clients.config
62  * ├── geoip
63  * │   ├── continents.txt
64  * │   ├── countries.txt
65  * │   ├── geoip.txt
66  * │   └── geoipv6.dat.gz
67  * ├── hosts.txt
68  * └── i2ptunnel.config
69  *
70  * @author Meeh
71  * @since 0.9.35
72  */
73class OSXDeployment extends
74  DeployProfile(
75    OSXDefaults.getOSXConfigDirectory.getAbsolutePath,
76    OSXDefaults.getOSXBaseDirectory.getAbsolutePath
77  ) {
78
79  /**
80    * This function will find the executing jar. "myself"
81    * @return
82    */
83  def executingJarFile = getClass().getProtectionDomain().getCodeSource().getLocation()
84
85
86  /**
87    * This list is a micro DSL for how files should
88    * be deployed to the filesystem in the base
89    * directory.
90    */
91  val staticFilesFromResources = List(
92    new FDObjFile("blocklist.txt"),
93    new FDObjFile("clients.config"),
94    new FDObjFile("hosts.txt"),
95    new FDObjDir("geoip", files = List(
96      "continents.txt",
97      "countries.txt",
98      "geoip.txt",
99      "geoipv6.dat.gz")),
100    new FDObjFile("i2ptunnel.config"),
101    new FDObjDir("certificates", List(
102      "family",
103      "i2ptunnel",
104      "news",
105      "plugin",
106      "reseed",
107      "revocations",
108      "router",
109      "ssl"
110    ),subDirectories=true),
111    new FDObjDir("themes",List(
112      "console",
113      "imagegen",
114      "snark",
115      "susidns",
116      "susimail"
117    ),true)
118  )
119
120  /**
121    * This function copies an directory of files from the jar
122    * to the base directory defined in the launcher.
123    * @param dir
124    * @return
125    */
126  def copyDirFromRes(dir: File): Unit = {
127    // A small hack
128    val zipFile = new ZipFile(executingJarFile.getFile)
129    zipFile.entries().asScala.toList.filter(_.toString.startsWith(dir.getPath)).filter(!_.isDirectory).map { entry =>
130      new File(DeployProfile.pathJoin(baseDir,entry.getName)).getParentFile.mkdirs()
131      if (entry.isDirectory) {
132        createFileOrDirectory(new File(DeployProfile.pathJoin(baseDir,entry.getName)), true)
133      } else {
134        copyBaseFileResToDisk(entry.getName, getClass.getResourceAsStream("/".concat(entry.getName)))
135      }
136    }
137  }
138
139  /**
140    * This function will depending on directory or not copy either the file
141    * or create the directory and copy directory content if any.
142    *
143    * @param file
144    * @param isDir
145    * @return
146    */
147  def createFileOrDirectory(file: File, isDir: Boolean = false): Unit = {
148    if (file != null) {
149      //println(s"createFileOrDirectory(${file},${isDir})")
150      try {
151        // Make sure subject exists if directory
152        if (!new File(DeployProfile.pathJoin(baseDir,file.getPath)).exists()) {
153          if (isDir) new File(DeployProfile.pathJoin(baseDir,file.getPath)).mkdirs()
154        }
155        if (isDir) {
156          // Handle dir
157          copyDirFromRes(file)
158        } else {
159          // Handle file
160          copyBaseFileResToDisk(file.getPath, getClass.getResourceAsStream("/".concat(file.getName)))
161        }
162      } catch {
163        case ex:IOException => println(s"Error! Exception ${ex}")
164      }
165    }
166  }
167
168  if (!new File(baseDir).exists()) {
169    new File(baseDir).mkdirs()
170  }
171
172  /**
173    * Please note that in Scala, the constructor body is same as class body.
174    * What's defined outside of methods is considered constructor code and
175    * executed as it.
176    *
177    *
178    *
179    * a map function work as a loop with some built in security
180    * for "null" objects.
181    * What happens here is "for each staticFilesFromResources" do =>
182    *
183    * Then, based upon if it's a file or a directory, different actions take place.
184    *
185    * the match case is controlling the flow based upon which type of object it is.
186    */
187  staticFilesFromResources.map {
188    fd => fd.getContent match {
189        // Case subject is a file/resource
190      case Left(is) => {
191        // Write file
192        if (!new File(DeployProfile.pathJoin(baseDir, fd.getPath)).exists()) {
193          //println(s"copyBaseFileResToDisk(${fd.getPath})")
194          try {
195            copyBaseFileResToDisk(fd.getPath, is)
196          } catch {
197            case ex:IOException => println(s"Error! Exception ${ex}")
198          }
199        }
200      }
201        // Case subject is a directory
202      case Right(dir) => {
203        // Ensure directory
204        //println(s"Directory(${fd.getPath})")
205        if (!new File(DeployProfile.pathJoin(baseDir,fd.getPath)).exists()) {
206          new File(DeployProfile.pathJoin(baseDir,fd.getPath)).mkdirs()
207        }
208        dir.map { f => createFileOrDirectory(f,fd.filesIsDirectories) }
209      }
210    }
211  }
212
213}
Note: See TracBrowser for help on using the repository browser.