Update local repository folder when there are changes in remote or some files are deleted in local with Jgit library - jgit

I'm trying for a couple of days to implement something that I was expecting to be easy. Use jGit library to clone a repository to a local folder and update the local folder to be always matching the remote. I've searched all over the place for a solution but the update part does not work, no matter what (clone works fine). Below is the code I have with both the clone and the update parts (the tries at least...) Can someone guide me on what am I missing here? Thanks in advance!
public class JgitTest {
public static void main(String[] args){
cloneRepository();
updateRepository();
checkRepo();
}
private static void cloneRepository() {
Git git = Git.cloneRepository()
.setURI("MY_URI")
.setBranchesToClone(Arrays.asList("refs/heads/main"))
.setDirectory(new File("C:\\A_FOLDER"))
.setCredentialsProvider(new UsernamePasswordCredentialsProvider("MYUSER", "MYPASSWORD"))
.call();
git = Git.open(new File("C:\\A_FOLDER"));
StoredConfig config = git.getRepository().getConfig();
config.setString("branch", "main", "merge", "refs/heads/main");
config.setString("branch", "main", "remote", "origin");
config.setString("remote", "origin", "fetch", "+refs/heads/*:refs/remotes/origin/*");
config.setString("remote", "origin", "url", "https://MYUSER#bitbucket.org/MYUSER/jGitTest.git");
config.save();
}
private static void checkRepo() {
Git git = Git.open(new File("C:\\A_FOLDER));
FetchResult result = git.fetch()
.setRemote("origin")
.setRefSpecs("refs/heads/main:refs/remotes/origin/main")
.setCredentialsProvider(new UsernamePasswordCredentialsProvider("MYUSER", "MYPASSWORD"))
.call();
}
private static void updateRepository() {
try {
Repository localRepo = new FileRepository("C:\\A_FOLDER" + "/.git");
Git git = new Git(localRepo);
CredentialsProvider cp = new UsernamePasswordCredentialsProvider("MYUSER", "MYPASSWORD");
git.fetch().setCredentialsProvider(cp).setForceUpdate(true).call();
git.pull().setCredentialsProvider(cp).setRebase(true).call();
git.close();
} catch (Exception e) {
}
}
}

The question is bit ambiguous. There are two types of updates on the any repo once its cloned. If you are talking in terms of getting latest changes like you are working on it, then you usually Pull or Fetch the latest changes.
If you are referring to backup of repositories so they can always contain the latest replica then you can use git clone with --mirror parameter to clone the repos initially and you use git remote update to update them subsequently.
JGit is just a simple wrapper on Git Protocol, use above git commands in your logic.

Related

dotnet core TopShelf Windows Service fails to start

I have a dotnet core console application build to connect to a Sql Service Broker instance to monitor table changes.
The app monitors one table that is updated from an ERP system and then publishes messages to our bus.
It runs fine when running as a console application, or debugging in my IDE.
I am having an issue when using TopShelf to configure it as a windows service.
Here is the entry point:
private static void Main(string[] args)
{
RegisterComponents();
var serviceHost = HostFactory.Run(sc =>
{
sc.Service<ISalesOrderMonitorService>(s =>
{
var sqlListener = _container.ResolveNamed<SqlDependencyEx>(ListenerKey.SalesOrder);
var changeHandler = _container.Resolve<ISalesOrderChangeHandler>();
var listenerConfig = _container.ResolveNamed<ListenerConfiguration>(ListenerKey.SalesOrder);
var logger = _container.Resolve<ILogger<SalesOrder>>();
s.ConstructUsing(f =>
new SalesOrderMonitorService(sqlListener, changeHandler, listenerConfig, logger));
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
});
var exitCode = (int) Convert.ChangeType(serviceHost, serviceHost.GetType());
Environment.ExitCode = exitCode;
}
The "worker" class:
public abstract class ServiceBase<T, TZ> : IService<T>
where T : IChangeHandler
{
protected readonly IChangeHandler ChangeHandler;
protected readonly SqlDependencyEx Listener;
protected readonly ListenerConfiguration ListenerConfiguration;
protected readonly ILogger<TZ> Logger;
protected ServiceBase(SqlDependencyEx listener, IChangeHandler changeHandler,
ListenerConfiguration listenerConfiguration, ILogger<TZ> logger)
{
Logger = logger;
ListenerConfiguration = listenerConfiguration;
Listener = listener;
ChangeHandler = changeHandler;
}
public virtual void Start()
{
try
{
Listener.TableChanged += (o, e) => ChangeHandler.Process(e);
Listener.Start();
Logger.LogDebug(
$"Listening to changes on the {ListenerConfiguration.Table} table in the {ListenerConfiguration.Database} database");
}
catch (Exception e)
{
Logger.LogError(e, e.Message);
throw;
}
}
public virtual void Stop()
{
Listener.Stop();
}
Install through TopShelf is no problem:
c:>{ServiceName}.exe install -username "serviceAccount" -password "superSecret" -servicename "ServiceName" -servicedescription "Description" -displayname "Service DisplayName" --autostart
When I go to start the service - I get this:
This is misleading because the event viewer shows this:
This is happening way faster than 30 seconds. This is definitely related to how I am configuring TopShelf.
As stated - the application works just fine when run "debug" or even as just an exe console.
I got it figured out. Actually both comments from #DotNetPadawan and #Lex Li indirectly got me there.
For starters - enabling the remote debugger clued me in that my appsetting.json was not being read into my IConfiguration. That was really confusing because everything works fine running locally with a debugger or even just starting the exe.
The link Lex Li points out did not provide the answer - however that article had this reference:
Host and Deploy aspnetcore as a Windows Service
It was here that I found this little nugget:
The current working directory returned by calling GetCurrentDirectory for a Windows Service is the C:\WINDOWS\system32 folder. The system32 folder isn't a suitable location to store a service's files (for example, settings files). Use one of the following approaches to maintain and access a service's assets and settings files.
The link explains how to conditionally set the current directory if the app is running as a service.
var isConsole = args.Contains("-mode:console");
if (!isConsole)
{
var pathToExe = Process.GetCurrentProcess().MainModule?.FileName;
var pathToContentRoot = Path.GetDirectoryName(pathToExe);
Directory.SetCurrentDirectory(pathToContentRoot);
}
Putting this out there for anyone else that runs into this problem.
Admittedly - netcore 3.0 is likely the better way to go - but I don't have the bandwidth to upgrade everything is this repo (lots of shared stuff) to 3.0. I needed to get this working.

WinSvc and Its Console version to Test

I have a ConsoleApp but I think to move it into a WinSvc application base. And I consider to move the soruce code as a library project and use it in both the old Console to TEST for other possible developments purpose and in the WinSvc for the real WORK area. Thus, when I add something new to the base library It will cause to appear in both apps. And It will be able to make my tests in the ConsoleApp environment and there will only need to rebuild for WinSvc part for real environment (It is to avoid to use the attached debug mode).
So, What can you say about this model? Or Is this a good approach? Or do you have any other suggestion?
This can be a solution:
public static void Main(string[] args)
{
MyWinSvcClass mySvc = new MyWinSvcClass();
if (Environment.UserInteractive)
{
// If the executable is started on console
mySvc.RunAsConsole(args);
}
else
{
// If the executable is started as a service
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { mySvc };
ServiceBase.Run(ServicesToRun);
}
}
Define RunAsConsole() In your service class:
public void RunAsConsole(string[] args)
{
Log("Service is started on console:");
OnStart(args);
Log("Service session is ended.");
OnStop();
}

Glassfish 5: specify document base to store the uploaded files on Server's file system [duplicate]

I read here that one should not save the file in the server anyway as it is not portable, transactional and requires external parameters. However, given that I need a tmp solution for tomcat (7) and that I have (relative) control over the server machine I want to know :
What is the best place to save the file ? Should I save it in /WEB-INF/uploads (advised against here) or someplace under $CATALINA_BASE (see here) or ... ? The JavaEE 6 tutorial gets the path from the user (:wtf:). NB : The file should not be downloadable by any means.
Should I set up a config parameter as detailed here ? I'd appreciate some code (I'd rather give it a relative path - so it is at least Tomcat portable) - Part.write() looks promising - but apparently needs a absolute path
I'd be interested in an exposition of the disadvantages of this approach vs a database/JCR repository one
Unfortunately the FileServlet by #BalusC concentrates on downloading files, while his answer on uploading files skips the part on where to save the file.
A solution easily convertible to use a DB or a JCR implementation (like jackrabbit) would be preferable.
Store it anywhere in an accessible location except of the IDE's project folder aka the server's deploy folder, for reasons mentioned in the answer to Uploaded image only available after refreshing the page:
Changes in the IDE's project folder does not immediately get reflected in the server's work folder. There's kind of a background job in the IDE which takes care that the server's work folder get synced with last updates (this is in IDE terms called "publishing"). This is the main cause of the problem you're seeing.
In real world code there are circumstances where storing uploaded files in the webapp's deploy folder will not work at all. Some servers do (either by default or by configuration) not expand the deployed WAR file into the local disk file system, but instead fully in the memory. You can't create new files in the memory without basically editing the deployed WAR file and redeploying it.
Even when the server expands the deployed WAR file into the local disk file system, all newly created files will get lost on a redeploy or even a simple restart, simply because those new files are not part of the original WAR file.
It really doesn't matter to me or anyone else where exactly on the local disk file system it will be saved, as long as you do not ever use getRealPath() method. Using that method is in any case alarming.
The path to the storage location can in turn be definied in many ways. You have to do it all by yourself. Perhaps this is where your confusion is caused because you somehow expected that the server does that all automagically. Please note that #MultipartConfig(location) does not specify the final upload destination, but the temporary storage location for the case file size exceeds memory storage threshold.
So, the path to the final storage location can be definied in either of the following ways:
Hardcoded:
File uploads = new File("/path/to/uploads");
Environment variable via SET UPLOAD_LOCATION=/path/to/uploads:
File uploads = new File(System.getenv("UPLOAD_LOCATION"));
VM argument during server startup via -Dupload.location="/path/to/uploads":
File uploads = new File(System.getProperty("upload.location"));
*.properties file entry as upload.location=/path/to/uploads:
File uploads = new File(properties.getProperty("upload.location"));
web.xml <context-param> with name upload.location and value /path/to/uploads:
File uploads = new File(getServletContext().getInitParameter("upload.location"));
If any, use the server-provided location, e.g. in JBoss AS/WildFly:
File uploads = new File(System.getProperty("jboss.server.data.dir"), "uploads");
Either way, you can easily reference and save the file as follows:
File file = new File(uploads, "somefilename.ext");
try (InputStream input = part.getInputStream()) {
Files.copy(input, file.toPath());
}
Or, when you want to autogenerate an unique file name to prevent users from overwriting existing files with coincidentally the same name:
File file = File.createTempFile("somefilename-", ".ext", uploads);
try (InputStream input = part.getInputStream()) {
Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
How to obtain part in JSP/Servlet is answered in How to upload files to server using JSP/Servlet? and how to obtain part in JSF is answered in How to upload file using JSF 2.2 <h:inputFile>? Where is the saved File?
Note: do not use Part#write() as it interprets the path relative to the temporary storage location defined in #MultipartConfig(location). Also make absolutely sure that you aren't corrupting binary files such as PDF files or image files by converting bytes to characters during reading/writing by incorrectly using a Reader/Writer instead of InputStream/OutputStream.
See also:
How to save uploaded file in JSF (JSF-targeted, but the principle is pretty much the same)
Simplest way to serve static data from outside the application server in a Java web application (in case you want to serve it back)
How to save generated file temporarily in servlet based web application
I post my final way of doing it based on the accepted answer:
#SuppressWarnings("serial")
#WebServlet("/")
#MultipartConfig
public final class DataCollectionServlet extends Controller {
private static final String UPLOAD_LOCATION_PROPERTY_KEY="upload.location";
private String uploadsDirName;
#Override
public void init() throws ServletException {
super.init();
uploadsDirName = property(UPLOAD_LOCATION_PROPERTY_KEY);
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// ...
}
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Collection<Part> parts = req.getParts();
for (Part part : parts) {
File save = new File(uploadsDirName, getFilename(part) + "_"
+ System.currentTimeMillis());
final String absolutePath = save.getAbsolutePath();
log.debug(absolutePath);
part.write(absolutePath);
sc.getRequestDispatcher(DATA_COLLECTION_JSP).forward(req, resp);
}
}
// helpers
private static String getFilename(Part part) {
// courtesy of BalusC : http://stackoverflow.com/a/2424824/281545
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String filename = cd.substring(cd.indexOf('=') + 1).trim()
.replace("\"", "");
return filename.substring(filename.lastIndexOf('/') + 1)
.substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
}
where :
#SuppressWarnings("serial")
class Controller extends HttpServlet {
static final String DATA_COLLECTION_JSP="/WEB-INF/jsp/data_collection.jsp";
static ServletContext sc;
Logger log;
// private
// "/WEB-INF/app.properties" also works...
private static final String PROPERTIES_PATH = "WEB-INF/app.properties";
private Properties properties;
#Override
public void init() throws ServletException {
super.init();
// synchronize !
if (sc == null) sc = getServletContext();
log = LoggerFactory.getLogger(this.getClass());
try {
loadProperties();
} catch (IOException e) {
throw new RuntimeException("Can't load properties file", e);
}
}
private void loadProperties() throws IOException {
try(InputStream is= sc.getResourceAsStream(PROPERTIES_PATH)) {
if (is == null)
throw new RuntimeException("Can't locate properties file");
properties = new Properties();
properties.load(is);
}
}
String property(final String key) {
return properties.getProperty(key);
}
}
and the /WEB-INF/app.properties :
upload.location=C:/_/
HTH and if you find a bug let me know

Windows Store Application Place SQLite File in LocalState Folder

I am building a Windows 8 application using sql-net and mvvmcross for data access to a sqlite database. This would be applicable to any Win-8 or Win-Phone app.
I need to install an existing sqlite file on app start.
When using the connection you use syntax such as this
public FlashCardManager(ISQLiteConnectionFactory factory, IMvxMessenger messenger)
{
_messenger = messenger;
_connection = factory.Create("Dictionary.sqlite");
_connection.CreateTable<FlashCardSet>();
_connection.CreateTable<FlashCard>();
}
public void CreateCard(FlashCard flashCard)
{
_connection.Insert(flashCard);
}
That connection creates a file in: C:\Users\USER\AppData\Local\Packages\793fd702-171e-474f-ab3b-d9067c58709b_ka9b83fa3fse2\LocalState
My application uses an existing sqlite database file that I have created. I need to place it in this folder when the application is installed. How would I go about doing this?
Thanks,
JH
Make sure you have the database file you want your app to start off with in one of your apps folders (as in the folders visible in visual studios solution explorer). For this example I'll call this folder "Assets"
All you need to do then is copy this file to the LocalState folder the first time your app runs. This can be done in App.xaml.cs
private async void InitializeAppEnvironment()
{
try
{
if (!(await AppHelper.ExistsInStorageFolder(AppHelper.localFolder, dbName)))
{
StorageFile defaultDb = await AppHelper.installedLocation.GetFileAsync("Assets\\" + dbName);
await defaultDb.CopyAsync(AppHelper.localFolder);
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e);
}
}
I made an AppHelper class to simplify accessing the app data folders, here's the parts I used above:
static class AppHelper
{
public static StorageFolder installedLocation = Windows.ApplicationModel.Package.Current.InstalledLocation;
public static StorageFolder localFolder = ApplicationData.Current.LocalFolder;
public static async Task<bool> ExistsInStorageFolder(this StorageFolder folder, string fileName)
{
try
{
await folder.GetFileAsync(fileName);
return true;
}
catch (FileNotFoundException)
{
return false;
}
}
}
For a more detailed response on MVVM cross I found the current discussion about cross platform file placement in this discussion: Link
The current thought is that you have to inject platform specific code for this sort of functionality.

When I try to start my Windows service, I get error number 1053

I am trying to pass a parameter to a Windows service, when I install the service using the command prompt in given manner shown below
d:\mypath>installutil -i service.exe -parameter
Before installing in program.cs file I have written in the following manner
static void Main(string[] args)
{
**string path = args[0];**
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
**new VibrantEmail(path)**
};
ServiceBase.Run(ServicesToRun);
}
and in service.cs page I have written this
**public VibrantEmail(string path)**
{
**data = path**
InitializeComponent();
}
The thing is like when I use static void Main(string[] args)
in program.cs page then only I get this error, number 1053.
Can anyone help me out?
You can't provide arguments at installation step. Installutil expects only assembly of which installer component will be executed. You will have to use Environment.GetCommandLineArgs to retrieve arguments in your code, then install service without providing parameters and modify its execution path based on this instructions.

Resources